[niepce/lr-import: 4/20] Basic Lr import




commit 16dd224e0230186efac676d9c6b9c17e55a89514
Author: Hubert Figuière <hub figuiere net>
Date:   Fri Nov 12 23:15:32 2021 -0500

    Basic Lr import
    
    - ncp-fwk: Added mime_guess and don't try to read exiv2
      metadata from missing files
    - npc-engine: Update rusqlite. Added lrcat-extractor.
      - added lrimport binary
      - move libraryclient to npc-engine

 Cargo.lock                                         | 223 ++++++++++++++-------
 crates/npc-engine/Cargo.toml                       |  16 +-
 crates/npc-engine/src/bin/importlr.rs              |  54 +++++
 crates/npc-engine/src/db/filebundle.rs             |   3 +-
 crates/npc-engine/src/db/library.rs                |  13 +-
 crates/npc-engine/src/importer.rs                  |  24 +++
 crates/npc-engine/src/importer/libraryimporter.rs  |  36 ++++
 crates/npc-engine/src/importer/lrimporter.rs       | 164 +++++++++++++++
 crates/npc-engine/src/lib.rs                       |   2 +
 crates/npc-engine/src/library/commands.rs          |  17 +-
 .../npc-engine}/src/libraryclient.rs               |  15 +-
 .../npc-engine}/src/libraryclient/clientimpl.rs    |  26 ++-
 .../src/libraryclient/clientinterface.rs           |  10 +-
 crates/npc-fwk/Cargo.toml                          |   1 +
 crates/npc-fwk/src/toolkit/mimetype.rs             |  14 +-
 crates/npc-fwk/src/utils/exempi.rs                 |   4 +
 niepce-main/src/lib.rs                             |   1 -
 niepce-main/src/niepce/ui/dialogs/importlibrary.rs |   2 +-
 .../src/niepce/ui/dialogs/requestnewfolder.rs      |   2 +-
 po/POTFILES.in                                     |   1 +
 src/Makefile.am                                    |   9 +-
 21 files changed, 523 insertions(+), 114 deletions(-)
---
diff --git a/Cargo.lock b/Cargo.lock
index e08ea03..a0c7e53 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4,9 +4,9 @@ version = 3
 
 [[package]]
 name = "ahash"
-version = "0.7.4"
+version = "0.7.6"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "43bb833f0bf979d8475d38fbf09ed3b8a55e1885fe93ad3f93239fc6a4f17b98"
+checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
 dependencies = [
  "getrandom",
  "once_cell",
@@ -24,9 +24,9 @@ dependencies = [
 
 [[package]]
 name = "anyhow"
-version = "1.0.41"
+version = "1.0.45"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "15af2628f6890fe2609a3b91bef4c83450512802e59489f9c1cb1fa5df064a61"
+checksum = "ee10e43ae4a853c0a3591d4e2ada1719e553be18199d9da9d4a83f5927c2f5c7"
 
 [[package]]
 name = "async-channel"
@@ -82,9 +82,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
 
 [[package]]
 name = "bitflags"
-version = "1.2.1"
+version = "1.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
 [[package]]
 name = "cache-padded"
@@ -94,9 +94,9 @@ checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba"
 
 [[package]]
 name = "cairo-rs"
-version = "0.14.0"
+version = "0.14.9"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "8d32eecb1e806433cf68063c4548bbdc15cc56d35db19d685ab60909c4c85206"
+checksum = "33b5725979db0c586d98abad2193cdb612dd40ef95cd26bd99851bf93b3cb482"
 dependencies = [
  "bitflags",
  "cairo-sys-rs",
@@ -107,9 +107,9 @@ dependencies = [
 
 [[package]]
 name = "cairo-sys-rs"
-version = "0.14.0"
+version = "0.14.9"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "d7c9c3928781e8a017ece15eace05230f04b647457d170d2d9641c94a444ff80"
+checksum = "b448b876970834fda82ba3aeaccadbd760206b75388fc5c1b02f1e343b697570"
 dependencies = [
  "glib-sys",
  "libc",
@@ -137,9 +137,9 @@ dependencies = [
 
 [[package]]
 name = "cfg-expr"
-version = "0.7.4"
+version = "0.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "30aa9e2ffbb838c6b451db14f3cd8e63ed622bf859f9956bc93845a10fafc26a"
+checksum = "b412e83326147c2bb881f8b40edfbf9905b9b8abaebd0e47ca190ba62fda8f0e"
 dependencies = [
  "smallvec",
 ]
@@ -242,24 +242,24 @@ dependencies = [
 
 [[package]]
 name = "futures-channel"
-version = "0.3.15"
+version = "0.3.17"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "e682a68b29a882df0545c143dc3646daefe80ba479bcdede94d5a703de2871e2"
+checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888"
 dependencies = [
  "futures-core",
 ]
 
 [[package]]
 name = "futures-core"
-version = "0.3.15"
+version = "0.3.17"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "0402f765d8a89a26043b889b26ce3c4679d268fa6bb22cd7c6aad98340e179d1"
+checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d"
 
 [[package]]
 name = "futures-executor"
-version = "0.3.15"
+version = "0.3.17"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "badaa6a909fac9e7236d0620a2f57f7664640c56575b71a7552fbd68deafab79"
+checksum = "45025be030969d763025784f7f355043dc6bc74093e4ecc5000ca4dc50d8745c"
 dependencies = [
  "futures-core",
  "futures-task",
@@ -268,21 +268,21 @@ dependencies = [
 
 [[package]]
 name = "futures-io"
-version = "0.3.15"
+version = "0.3.17"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "acc499defb3b348f8d8f3f66415835a9131856ff7714bf10dadfc4ec4bdb29a1"
+checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377"
 
 [[package]]
 name = "futures-task"
-version = "0.3.15"
+version = "0.3.17"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "8a16bef9fc1a4dddb5bee51c989e3fbba26569cbb0e31f5b303c184e3dd33dae"
+checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99"
 
 [[package]]
 name = "futures-util"
-version = "0.3.15"
+version = "0.3.17"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "feb5c238d27e2bf94ffdfd27b2c29e3df4a68c4193bb6427384259e2bf191967"
+checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481"
 dependencies = [
  "autocfg",
  "futures-core",
@@ -294,9 +294,9 @@ dependencies = [
 
 [[package]]
 name = "gdk"
-version = "0.14.0"
+version = "0.14.3"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "679e22651cd15888e7acd01767950edca2ee9fcd6421fbf5b3c3b420d4e88bb0"
+checksum = "b9d749dcfc00d8de0d7c3a289e04a04293eb5ba3d8a4e64d64911d481fa9933b"
 dependencies = [
  "bitflags",
  "cairo-rs",
@@ -379,9 +379,9 @@ dependencies = [
 
 [[package]]
 name = "gio"
-version = "0.14.0"
+version = "0.14.8"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "86c6823b39d46d22cac2466de261f28d7f049ebc18f7b35296a42c7ed8a88325"
+checksum = "711c3632b3ebd095578a9c091418d10fed492da9443f58ebc8f45efbeb215cb0"
 dependencies = [
  "bitflags",
  "futures-channel",
@@ -409,9 +409,9 @@ dependencies = [
 
 [[package]]
 name = "glib"
-version = "0.14.2"
+version = "0.14.8"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "dbecad7a3a898ee749d491ce2ae0decb0bce9e736f9747bc49159b1cea5d37f4"
+checksum = "7c515f1e62bf151ef6635f528d05b02c11506de986e43b34a5c920ef0b3796a4"
 dependencies = [
  "bitflags",
  "futures-channel",
@@ -428,9 +428,9 @@ dependencies = [
 
 [[package]]
 name = "glib-macros"
-version = "0.14.0"
+version = "0.14.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "9eb7bdf41972a6f6dab5d72c23d22789f400059a43ba0d72b4bb2f8664d946a9"
+checksum = "2aad66361f66796bfc73f530c51ef123970eb895ffba991a234fcf7bea89e518"
 dependencies = [
  "anyhow",
  "heck",
@@ -464,9 +464,9 @@ dependencies = [
 
 [[package]]
 name = "gtk"
-version = "0.14.0"
+version = "0.14.3"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "10ae864e5eab8bc8b6b8544ed259eb02dd61b25323b20e777a77aa289c05fd0c"
+checksum = "2eb51122dd3317e9327ec1e4faa151d1fa0d95664cd8fb8dcfacf4d4d29ac70c"
 dependencies = [
  "atk",
  "bitflags",
@@ -575,9 +575,9 @@ dependencies = [
 
 [[package]]
 name = "itoa"
-version = "0.4.7"
+version = "0.4.8"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
+checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
 
 [[package]]
 name = "lazy_static"
@@ -587,9 +587,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 
 [[package]]
 name = "libc"
-version = "0.2.97"
+version = "0.2.107"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6"
+checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219"
 
 [[package]]
 name = "libopenraw-rs"
@@ -607,9 +607,9 @@ dependencies = [
 
 [[package]]
 name = "libsqlite3-sys"
-version = "0.22.2"
+version = "0.23.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "290b64917f8b0cb885d9de0f9959fe1f775d7fa12f1da2db9001c1c8ab60f89d"
+checksum = "abd5850c449b40bacb498b2bbdfaff648b1b055630073ba8db499caf2d0ea9f2"
 dependencies = [
  "pkg-config",
  "vcpkg",
@@ -624,6 +624,17 @@ dependencies = [
  "cfg-if",
 ]
 
+[[package]]
+name = "lrcat-extractor"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "ee7ae5136c7085d85886d3a31e9bda2bce03c750b143beca4d8d1073e30bef7e"
+dependencies = [
+ "chrono",
+ "peg",
+ "rusqlite",
+]
+
 [[package]]
 name = "maplit"
 version = "1.0.2"
@@ -632,9 +643,9 @@ checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
 
 [[package]]
 name = "memchr"
-version = "2.4.0"
+version = "2.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
+checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
 
 [[package]]
 name = "memoffset"
@@ -645,6 +656,22 @@ dependencies = [
  "autocfg",
 ]
 
+[[package]]
+name = "mime"
+version = "0.3.16"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
+
+[[package]]
+name = "mime_guess"
+version = "2.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "2684d4c2e97d99848d30b324b00c8fcc7e5c897b7cbb5819b09e7c90e8baf212"
+dependencies = [
+ "mime",
+ "unicase",
+]
+
 [[package]]
 name = "multimap"
 version = "0.4.0"
@@ -683,12 +710,15 @@ dependencies = [
  "async-channel",
  "cbindgen",
  "chrono",
+ "clap",
  "exempi",
  "gdk-pixbuf",
  "gdk-pixbuf-sys",
+ "gettext-rs",
  "glib",
  "lazy_static",
  "libc",
+ "lrcat-extractor",
  "maplit",
  "npc-fwk",
  "rusqlite",
@@ -715,6 +745,7 @@ dependencies = [
  "lazy_static",
  "libc",
  "libopenraw-rs",
+ "mime_guess",
  "multimap",
  "once_cell",
  "rexiv2",
@@ -758,9 +789,9 @@ checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
 
 [[package]]
 name = "pango"
-version = "0.14.0"
+version = "0.14.8"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "415823a4fb9f1789785cd6e2d2413816f2ecff92380382969aaca9c400e13a19"
+checksum = "546fd59801e5ca735af82839007edd226fe7d3bb06433ec48072be4439c28581"
 dependencies = [
  "bitflags",
  "glib",
@@ -781,6 +812,33 @@ dependencies = [
  "system-deps",
 ]
 
+[[package]]
+name = "peg"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "07c0b841ea54f523f7aa556956fbd293bcbe06f2e67d2eb732b7278aaf1d166a"
+dependencies = [
+ "peg-macros",
+ "peg-runtime",
+]
+
+[[package]]
+name = "peg-macros"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "b5aa52829b8decbef693af90202711348ab001456803ba2a98eb4ec8fb70844c"
+dependencies = [
+ "peg-runtime",
+ "proc-macro2",
+ "quote",
+]
+
+[[package]]
+name = "peg-runtime"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "c719dcf55f09a3a7e764c6649ab594c18a177e3599c467983cdf644bfc0a4088"
+
 [[package]]
 name = "pest"
 version = "2.1.3"
@@ -804,21 +862,21 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
 
 [[package]]
 name = "pkg-config"
-version = "0.3.19"
+version = "0.3.22"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
+checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f"
 
 [[package]]
 name = "ppv-lite86"
-version = "0.2.10"
+version = "0.2.15"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
+checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba"
 
 [[package]]
 name = "proc-macro-crate"
-version = "1.0.0"
+version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "41fdbd1df62156fbc5945f4762632564d7d038153091c3fcf1067f6aef7cff92"
+checksum = "1ebace6889caf889b4d3f76becee12e90353f2b8c7d875534a71e5742f8f6f83"
 dependencies = [
  "thiserror",
  "toml",
@@ -850,18 +908,18 @@ dependencies = [
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.27"
+version = "1.0.32"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038"
+checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43"
 dependencies = [
  "unicode-xid",
 ]
 
 [[package]]
 name = "quote"
-version = "1.0.9"
+version = "1.0.10"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
+checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
 dependencies = [
  "proc-macro2",
 ]
@@ -908,9 +966,9 @@ dependencies = [
 
 [[package]]
 name = "redox_syscall"
-version = "0.2.9"
+version = "0.2.10"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "5ab49abadf3f9e1c4bc499e8845e152ad87d2ad2d30371841171169e9d75feee"
+checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
 dependencies = [
  "bitflags",
 ]
@@ -937,9 +995,9 @@ dependencies = [
 
 [[package]]
 name = "rusqlite"
-version = "0.25.3"
+version = "0.26.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "57adcf67c8faaf96f3248c2a7b419a0dbc52ebe36ba83dd57fe83827c1ea4eb3"
+checksum = "8a82b0b91fad72160c56bf8da7a549b25d7c31109f52cc1437eac4c0ad2550a7"
 dependencies = [
  "bitflags",
  "fallible-iterator",
@@ -985,18 +1043,18 @@ dependencies = [
 
 [[package]]
 name = "serde"
-version = "1.0.126"
+version = "1.0.130"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03"
+checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.126"
+version = "1.0.130"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43"
+checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1005,9 +1063,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.64"
+version = "1.0.69"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79"
+checksum = "e466864e431129c7e0d3476b92f20458e5879919a0596c6472738d9fa2d342f8"
 dependencies = [
  "itoa",
  "ryu",
@@ -1016,15 +1074,15 @@ dependencies = [
 
 [[package]]
 name = "slab"
-version = "0.4.3"
+version = "0.4.5"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527"
+checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5"
 
 [[package]]
 name = "smallvec"
-version = "1.6.1"
+version = "1.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
+checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
 
 [[package]]
 name = "strsim"
@@ -1052,9 +1110,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "1.0.73"
+version = "1.0.81"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7"
+checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1063,9 +1121,9 @@ dependencies = [
 
 [[package]]
 name = "system-deps"
-version = "3.1.2"
+version = "3.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "7ab7dbd121ce66af2176147a48c7e01aaf1f001837a18a7cf4317858606bbdf8"
+checksum = "480c269f870722b3b08d2f13053ce0c2ab722839f472863c3e2d61ff3a1c2fa6"
 dependencies = [
  "anyhow",
  "cfg-expr",
@@ -1104,18 +1162,18 @@ dependencies = [
 
 [[package]]
 name = "thiserror"
-version = "1.0.26"
+version = "1.0.30"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2"
+checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.26"
+version = "1.0.30"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745"
+checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1147,6 +1205,15 @@ version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
 
+[[package]]
+name = "unicase"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
+dependencies = [
+ "version_check",
+]
+
 [[package]]
 name = "unicode-segmentation"
 version = "1.8.0"
@@ -1155,9 +1222,9 @@ checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
 
 [[package]]
 name = "unicode-width"
-version = "0.1.8"
+version = "0.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
+checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
 
 [[package]]
 name = "unicode-xid"
diff --git a/crates/npc-engine/Cargo.toml b/crates/npc-engine/Cargo.toml
index 625bc06..ddf7792 100644
--- a/crates/npc-engine/Cargo.toml
+++ b/crates/npc-engine/Cargo.toml
@@ -4,22 +4,34 @@ version = "0.1.0"
 authors = ["Hubert Figuière <hub figuiere net>"]
 edition = "2018"
 build = "build.rs"
+description = "The Niepce engine. Internal crate."
+license = "GPL-3.0"
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
 async-channel = "1.6.1"
-chrono = "0.4.0"
+clap = { version = "2.33.3", optional = true }
+chrono = "0.4.19"
 exempi = { version = "2.6.0", git = "https://github.com/hfiguiere/exempi-rs.git";, rev="99e8ba5" }
+gettext-rs = "0.3.0"
 gdk-pixbuf-sys = "*"
 gdk-pixbuf = "*"
 glib = "*"
 lazy_static = "^1.2.0"
 libc = "0.2.39"
 maplit = "1.0.2"
-rusqlite = { version = "0.25.3", features = ["functions"] }
+lrcat-extractor = { version = "0.1.0" }
+rusqlite = { version = "0.26.1", features = ["functions"] }
 
 npc-fwk = { path = "../npc-fwk" }
 
 [build-dependencies]
 cbindgen = { version = "0.19.0" }
+
+[[bin]]
+name = "importlr"
+required-features = ["binaries"]
+
+[features]
+binaries = ["clap"]
diff --git a/crates/npc-engine/src/bin/importlr.rs b/crates/npc-engine/src/bin/importlr.rs
new file mode 100644
index 0000000..b26d8a6
--- /dev/null
+++ b/crates/npc-engine/src/bin/importlr.rs
@@ -0,0 +1,54 @@
+use clap::{App, Arg};
+use gettextrs::*;
+use std::path::PathBuf;
+
+use npc_engine::importer::LibraryImporter;
+use npc_engine::importer::LrImporter;
+use npc_engine::libraryclient::LibraryClient;
+
+fn main() {
+    setlocale(LocaleCategory::LcAll, "");
+    bind_textdomain_codeset("importlr", "UTF-8");
+    textdomain("importlr");
+
+    npc_fwk::init();
+
+    let matches = App::new("LrImporter")
+        .version("0.1.0")
+        .about("Import a Lr catalog")
+        .arg(
+            Arg::with_name("v")
+                .short("v")
+                .multiple(true)
+                .help("Sets the level of verbosity"),
+        )
+        .arg(
+            Arg::with_name("CATALOG")
+                .help("The catalog to import")
+                .required(true),
+        )
+        .arg(
+            Arg::with_name("library")
+                .short("L")
+                .value_name("LIBRARY")
+                .help("Which library to import into")
+                .required(true)
+                .takes_value(true),
+        )
+        .get_matches();
+
+    let library = matches.value_of("library").unwrap();
+    let catalog = matches.value_of("CATALOG").unwrap();
+    let verbosity = matches.occurrences_of("v");
+
+    let (sender, recv) = async_channel::unbounded();
+
+    let mut library = LibraryClient::new(PathBuf::from(library), sender);
+    // library.init();
+    let mut importer = LrImporter::new();
+    if !LrImporter::can_import_library(&PathBuf::from(catalog)) {
+        println!("Can't import catalog {}", catalog);
+        return;
+    }
+    if importer.import_library(&PathBuf::from(catalog), &mut library) {}
+}
diff --git a/crates/npc-engine/src/db/filebundle.rs b/crates/npc-engine/src/db/filebundle.rs
index 0add42a..a5beaf4 100644
--- a/crates/npc-engine/src/db/filebundle.rs
+++ b/crates/npc-engine/src/db/filebundle.rs
@@ -25,7 +25,7 @@ use npc_fwk::toolkit::mimetype::{IsRaw, MType};
 use npc_fwk::MimeType;
 
 /// Sidecar.
-#[derive(Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq)]
 pub enum Sidecar {
     Invalid,
     /// Sidecar for Live image (MOV file form iPhone)
@@ -64,6 +64,7 @@ impl From<(i32, PathBuf)> for Sidecar {
 
 /// FileBundle is a set of physical files group as one item.
 /// Mostly sticking to the DCF specification.
+#[derive(Clone)]
 pub struct FileBundle {
     /// Type of bundle
     bundle_type: FileType,
diff --git a/crates/npc-engine/src/db/library.rs b/crates/npc-engine/src/db/library.rs
index cd3f69d..d5decf7 100644
--- a/crates/npc-engine/src/db/library.rs
+++ b/crates/npc-engine/src/db/library.rs
@@ -131,10 +131,15 @@ impl Library {
             sender,
         };
 
-        if let Ok(conn) = rusqlite::Connection::open(dbpath) {
-            lib.dbconn = Some(conn);
-            lib.inited = lib.init().is_ok();
-        }
+        match rusqlite::Connection::open(dbpath) {
+            Ok(conn) => {
+                lib.dbconn = Some(conn);
+                lib.inited = lib.init().is_ok();
+            }
+            Err(err) => {
+                err_out!("open failed {:?}", err);
+            }
+        };
 
         lib
     }
diff --git a/crates/npc-engine/src/importer.rs b/crates/npc-engine/src/importer.rs
new file mode 100644
index 0000000..455686e
--- /dev/null
+++ b/crates/npc-engine/src/importer.rs
@@ -0,0 +1,24 @@
+/*
+ * niepce - engine/importer/mod.rs
+ *
+ * Copyright (C) 2021 Hubert Figuière
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+pub mod libraryimporter;
+pub mod lrimporter;
+
+pub use libraryimporter::LibraryImporter;
+pub use lrimporter::LrImporter;
diff --git a/crates/npc-engine/src/importer/libraryimporter.rs 
b/crates/npc-engine/src/importer/libraryimporter.rs
new file mode 100644
index 0000000..167074a
--- /dev/null
+++ b/crates/npc-engine/src/importer/libraryimporter.rs
@@ -0,0 +1,36 @@
+/*
+ * niepce - engine/importer/libraryimporter.rs
+ *
+ * Copyright (C) 2021 Hubert Figuière
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+use std::path::Path;
+
+use crate::libraryclient::LibraryClient;
+
+/// Interface trait for a library importer.
+pub trait LibraryImporter {
+    /// Return a new library importer
+    fn new() -> Self;
+
+    /// import the library at path.
+    /// if can_import_library returne false this should return false
+    /// XXX return an actual Result<>
+    fn import_library(&mut self, path: &Path, libclient: &mut LibraryClient) -> bool;
+
+    /// Return true if or a given path the importer recognize the library
+    fn can_import_library(path: &Path) -> bool;
+}
diff --git a/crates/npc-engine/src/importer/lrimporter.rs b/crates/npc-engine/src/importer/lrimporter.rs
new file mode 100644
index 0000000..f7e16f8
--- /dev/null
+++ b/crates/npc-engine/src/importer/lrimporter.rs
@@ -0,0 +1,164 @@
+/*
+ * niepce - npc-engine/importer/lrimporter.rs
+ *
+ * Copyright (C) 2021 Hubert Figuière
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+use gettextrs::gettext;
+
+use std::collections::BTreeMap;
+use std::path::Path;
+
+use lrcat::{Catalog, CatalogVersion, Folder, Keyword, KeywordTree, LibraryFile, LrId, LrObject};
+
+use super::libraryimporter::LibraryImporter;
+use crate::db::filebundle::FileBundle;
+use crate::db::LibraryId;
+use crate::libraryclient::{ClientInterfaceSync, LibraryClient};
+
+/// Library importer for Lightroom
+pub struct LrImporter {
+    /// map keyword LrId to LibraryId
+    folder_map: BTreeMap<LrId, (LibraryId, String)>,
+    /// map keyword LrId to LibraryId
+    keyword_map: BTreeMap<LrId, LibraryId>,
+    /// map collection LrId to album LibraryId
+    collection_map: BTreeMap<LrId, LibraryId>,
+    /// map files LrId to file LibraryId
+    file_map: BTreeMap<LrId, LibraryId>,
+}
+
+impl LrImporter {
+    /// Import keyword with `id`. `keywords` is all the Lr keywords, `tree`
+    /// is the hierarchy tree as returned by `Catalog::load_keywords_tree()`
+    fn import_keyword(
+        &mut self,
+        id: LrId,
+        mut libclient: &mut LibraryClient,
+        keywords: &BTreeMap<LrId, Keyword>,
+        tree: &KeywordTree,
+    ) {
+        if let Some(keyword) = keywords.get(&id) {
+            let nid = libclient.create_keyword_sync(keyword.name.clone());
+            self.keyword_map.insert(id, nid);
+            tree.children_for(id).iter().for_each(|child| {
+                self.import_keyword(*child, &mut libclient, keywords, tree);
+            });
+        }
+    }
+
+    fn import_folder(&mut self, folder: &Folder, path: &str, libclient: &mut LibraryClient) {
+        let folder_name = Path::new(&path)
+            .file_name()
+            .map(|name| String::from(name.to_string_lossy()))
+            .unwrap_or_else(|| gettext("Untitled"));
+        let nid = libclient.create_folder_sync(folder_name, Some(path.into()));
+        self.folder_map.insert(folder.id(), (nid, path.into()));
+    }
+
+    fn import_library_file(&mut self, file: &LibraryFile, libclient: &mut LibraryClient) {
+        if let Some(folder_id) = self.folder_map.get(&file.folder) {
+            let main_file = format!("{}/{}.{}", &folder_id.1, &file.basename, &file.extension);
+            let mut xmp_file: Option<String> = None;
+            let mut jpeg_file: Option<String> = None;
+            let sidecar_exts = file.sidecar_extensions.split(",");
+            sidecar_exts.for_each(|ext| {
+                if ext.to_lowercase() == "xmp" {
+                    xmp_file = Some(format!("{}/{}.{}", &folder_id.1, &file.basename, &ext));
+                } else {
+                    if jpeg_file.is_some() {
+                        err_out!("JPEG sidecar already set: {}", ext);
+                    } else {
+                        jpeg_file = Some(format!("{}/{}.{}", &folder_id.1, &file.basename, &ext));
+                    }
+                }
+            });
+
+            let mut bundle = FileBundle::new();
+            dbg_out!("Adding {}", &main_file);
+            bundle.add(main_file);
+            if let Some(jpeg_file) = jpeg_file {
+                dbg_out!("Adding JPEG {}", &jpeg_file);
+                bundle.add(jpeg_file);
+            }
+            if let Some(xmp_file) = xmp_file {
+                dbg_out!("Adding XMP {}", &xmp_file);
+                bundle.add(xmp_file);
+            }
+            let nid = libclient.add_bundle_sync(&bundle, folder_id.0);
+            self.file_map.insert(file.id(), nid);
+        }
+    }
+}
+
+impl LibraryImporter for LrImporter {
+    fn new() -> LrImporter {
+        LrImporter {
+            folder_map: BTreeMap::new(),
+            keyword_map: BTreeMap::new(),
+            collection_map: BTreeMap::new(),
+            file_map: BTreeMap::new(),
+        }
+    }
+
+    fn import_library(&mut self, path: &Path, libclient: &mut LibraryClient) -> bool {
+        let mut catalog = Catalog::new(path);
+        if !catalog.open() {
+            return false;
+        }
+
+        catalog.load_version();
+        if catalog.catalog_version != CatalogVersion::Lr4 {
+            return false;
+        }
+
+        let folders = catalog.load_folders();
+        folders.folders.iter().for_each(|folder| {
+            if let Some(path) = folders.resolve_folder_path(folder) {
+                self.import_folder(&folder, &path, libclient);
+            }
+        });
+
+        let root_keyword_id = catalog.root_keyword_id;
+        let keywordtree = catalog.load_keywords_tree();
+        let keywords = catalog.load_keywords();
+        self.import_keyword(root_keyword_id, libclient, keywords, &keywordtree);
+
+        let collections = catalog.load_collections();
+        collections.iter().for_each(|collection| {
+            if !collection.system_only {
+                dbg_out!("Found collection {}", collection.name);
+            }
+        });
+
+        let library_files = catalog.load_library_files();
+        library_files.iter().for_each(|library_file| {
+            self.import_library_file(library_file, libclient);
+        });
+        true
+    }
+
+    /// Detect if this is a Lr catalog
+    /// XXX improve it.
+    fn can_import_library(path: &Path) -> bool {
+        if let Some(ext) = path.extension() {
+            if ext == "lrcat" {
+                return true;
+            }
+        }
+        false
+    }
+}
diff --git a/crates/npc-engine/src/lib.rs b/crates/npc-engine/src/lib.rs
index 86c6901..f6b881c 100644
--- a/crates/npc-engine/src/lib.rs
+++ b/crates/npc-engine/src/lib.rs
@@ -25,7 +25,9 @@ extern crate glib;
 extern crate npc_fwk;
 
 pub mod db;
+pub mod importer;
 pub mod library;
+pub mod libraryclient;
 
 use std::ptr;
 
diff --git a/crates/npc-engine/src/library/commands.rs b/crates/npc-engine/src/library/commands.rs
index 28c87fc..6ecc0c1 100644
--- a/crates/npc-engine/src/library/commands.rs
+++ b/crates/npc-engine/src/library/commands.rs
@@ -132,12 +132,27 @@ pub fn cmd_import_files(lib: &Library, folder: &str, files: &[PathBuf], manage:
     }
 }
 
+pub fn cmd_add_bundle(lib: &Library, bundle: &FileBundle, folder: LibraryId) -> LibraryId {
+    match lib.add_bundle(folder, bundle, library::Managed::NO) {
+        Ok(id) => {
+            if lib.notify(LibNotification::AddedFiles).is_err() {
+                err_out!("Failed to notify AddedFiles");
+            }
+            id
+        }
+        Err(err) => {
+            err_out_line!("Bundle creation failed {:?}", err);
+            -1
+        }
+    }
+}
+
 pub fn cmd_create_folder(lib: &Library, name: &str, path: Option<String>) -> LibraryId {
     match lib.add_folder(name, path) {
         Ok(lf) => {
             let id = lf.id();
             if lib.notify(LibNotification::AddedFolder(lf)).is_err() {
-                err_out!("Failed to notifu AddedFolder");
+                err_out!("Failed to notify AddedFolder");
             }
             id
         }
diff --git a/niepce-main/src/libraryclient.rs b/crates/npc-engine/src/libraryclient.rs
similarity index 96%
rename from niepce-main/src/libraryclient.rs
rename to crates/npc-engine/src/libraryclient.rs
index b0e28fe..38207cf 100644
--- a/niepce-main/src/libraryclient.rs
+++ b/crates/npc-engine/src/libraryclient.rs
@@ -28,11 +28,12 @@ use std::path::PathBuf;
 use std::sync::Arc;
 
 use self::clientimpl::ClientImpl;
-use npc_engine::db::library::Managed;
-use npc_engine::db::props::NiepceProperties as Np;
-use npc_engine::db::LibraryId;
-use npc_engine::db::{NiepceProperties, NiepcePropertyIdx};
-use npc_engine::library::notification::{LcChannel, LibNotification};
+use crate::db::filebundle::FileBundle;
+use crate::db::library::Managed;
+use crate::db::props::NiepceProperties as Np;
+use crate::db::LibraryId;
+use crate::db::{NiepceProperties, NiepcePropertyIdx};
+use crate::library::notification::{LcChannel, LibNotification};
 use npc_fwk::base::PropertyValue;
 use npc_fwk::toolkit::PortableChannel;
 use npc_fwk::utils::files::FileList;
@@ -169,6 +170,10 @@ impl ClientInterfaceSync for LibraryClient {
     fn create_folder_sync(&mut self, name: String, path: Option<String>) -> LibraryId {
         self.pimpl.create_folder_sync(name, path)
     }
+
+    fn add_bundle_sync(&mut self, bundle: &FileBundle, folder: LibraryId) -> LibraryId {
+        self.pimpl.add_bundle_sync(bundle, folder)
+    }
 }
 
 #[no_mangle]
diff --git a/niepce-main/src/libraryclient/clientimpl.rs b/crates/npc-engine/src/libraryclient/clientimpl.rs
similarity index 92%
rename from niepce-main/src/libraryclient/clientimpl.rs
rename to crates/npc-engine/src/libraryclient/clientimpl.rs
index c24104c..41804c7 100644
--- a/niepce-main/src/libraryclient/clientimpl.rs
+++ b/crates/npc-engine/src/libraryclient/clientimpl.rs
@@ -25,12 +25,13 @@ use std::sync::mpsc;
 use std::thread;
 
 use super::clientinterface::{ClientInterface, ClientInterfaceSync};
-use npc_engine::db::library::Managed;
-use npc_engine::db::props::NiepceProperties as Np;
-use npc_engine::db::{Library, LibraryId};
-use npc_engine::library::commands;
-use npc_engine::library::notification::LibNotification;
-use npc_engine::library::op::Op;
+use crate::db::filebundle::FileBundle;
+use crate::db::library::Managed;
+use crate::db::props::NiepceProperties as Np;
+use crate::db::{Library, LibraryId};
+use crate::library::commands;
+use crate::library::notification::LibNotification;
+use crate::library::op::Op;
 use npc_fwk::base::PropertyValue;
 
 pub struct ClientImpl {
@@ -230,4 +231,17 @@ impl ClientInterfaceSync for ClientImpl {
 
         rx.recv().unwrap()
     }
+
+    fn add_bundle_sync(&mut self, bundle: &FileBundle, folder: LibraryId) -> LibraryId {
+        let (tx, rx) = mpsc::sync_channel::<LibraryId>(1);
+
+        let bundle = bundle.clone();
+        self.schedule_op(move |lib| {
+            tx.send(commands::cmd_add_bundle(&lib, &bundle, folder))
+                .unwrap();
+            true
+        });
+
+        rx.recv().unwrap()
+    }
 }
diff --git a/niepce-main/src/libraryclient/clientinterface.rs 
b/crates/npc-engine/src/libraryclient/clientinterface.rs
similarity index 91%
rename from niepce-main/src/libraryclient/clientinterface.rs
rename to crates/npc-engine/src/libraryclient/clientinterface.rs
index f7d159a..88aaa1f 100644
--- a/niepce-main/src/libraryclient/clientinterface.rs
+++ b/crates/npc-engine/src/libraryclient/clientinterface.rs
@@ -19,9 +19,10 @@
 
 use std::path::PathBuf;
 
-use npc_engine::db::library::Managed;
-use npc_engine::db::props::NiepceProperties as Np;
-use npc_engine::db::LibraryId;
+use crate::db::filebundle::FileBundle;
+use crate::db::library::Managed;
+use crate::db::props::NiepceProperties as Np;
+use crate::db::LibraryId;
 use npc_fwk::base::PropertyValue;
 
 /// Client interface.
@@ -72,4 +73,7 @@ pub trait ClientInterfaceSync {
 
     /// Create a folder. Return the id of the newly created folder.
     fn create_folder_sync(&mut self, name: String, path: Option<String>) -> LibraryId;
+
+    /// Add a bundle.
+    fn add_bundle_sync(&mut self, bundle: &FileBundle, folder: LibraryId) -> LibraryId;
 }
diff --git a/crates/npc-fwk/Cargo.toml b/crates/npc-fwk/Cargo.toml
index e129245..96c2eac 100644
--- a/crates/npc-fwk/Cargo.toml
+++ b/crates/npc-fwk/Cargo.toml
@@ -26,6 +26,7 @@ libc = "0.2.39"
 libopenraw-rs = { path = "../../../libopenraw-rs/libopenraw-rs" }
 # { git = "https://gitlab.freedesktop.org/libopenraw/libopenraw-rs.git";, rev = 
"edae9f8771fa4f4b577ef2e56d9dbd6f68d97105" }
 multimap = "0.4.0"
+mime_guess = "2.0.3"
 once_cell = "1.8.0"
 rexiv2 = "^0.9.1"
 
diff --git a/crates/npc-fwk/src/toolkit/mimetype.rs b/crates/npc-fwk/src/toolkit/mimetype.rs
index f8fc292..b08531b 100644
--- a/crates/npc-fwk/src/toolkit/mimetype.rs
+++ b/crates/npc-fwk/src/toolkit/mimetype.rs
@@ -1,7 +1,7 @@
 /*
  * niepce - fwk/toolkit/mimetype.rs
  *
- * Copyright (C) 2017-2020 Hubert Figuière
+ * Copyright (C) 2017-2021 Hubert Figuière
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -17,8 +17,6 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-use gio::prelude::*;
-
 use std::convert::AsRef;
 use std::path::Path;
 
@@ -57,16 +55,16 @@ pub fn guess_type(gmtype: &str) -> MType {
 /// Guess the type from a file
 fn guess_type_for_file<P: AsRef<Path>>(p: P) -> MType {
     let path = p.as_ref();
-    let file = gio::File::for_path(path);
-    let cancellable: Option<&gio::Cancellable> = None;
-    if let Ok(fileinfo) = file.query_info("*", gio::FileQueryInfoFlags::NONE, cancellable) {
-        if let Some(gmtype) = fileinfo.content_type() {
-            let t = guess_type(&gmtype);
+    let guess = mime_guess::from_path(path);
+    if !guess.is_empty() {
+        if let Some(mime) = guess.first_raw() {
+            let t = guess_type(mime);
             if t != MType::None {
                 return t;
             }
         }
     }
+
     if let Some(ext) = path.extension() {
         match ext.to_str() {
             Some("xmp") => return MType::Xmp,
diff --git a/crates/npc-fwk/src/utils/exempi.rs b/crates/npc-fwk/src/utils/exempi.rs
index 07c4be3..f20ad65 100644
--- a/crates/npc-fwk/src/utils/exempi.rs
+++ b/crates/npc-fwk/src/utils/exempi.rs
@@ -182,6 +182,10 @@ impl XmpMeta {
         P: AsRef<Path> + AsRef<OsStr>,
     {
         let file: &Path = p.as_ref();
+        if !file.exists() {
+            err_out!("File {:?} doesn't exist", &file);
+            return None;
+        }
         let mut meta: Option<XmpMeta> = None;
         if !sidecar_only {
             if let Ok(xmpfile) =
diff --git a/niepce-main/src/lib.rs b/niepce-main/src/lib.rs
index ccc5c10..18aa822 100644
--- a/niepce-main/src/lib.rs
+++ b/niepce-main/src/lib.rs
@@ -36,7 +36,6 @@ extern crate once_cell;
 extern crate npc_fwk;
 extern crate npc_engine;
 
-pub mod libraryclient;
 pub mod niepce;
 
 use std::sync::Once;
diff --git a/niepce-main/src/niepce/ui/dialogs/importlibrary.rs 
b/niepce-main/src/niepce/ui/dialogs/importlibrary.rs
index f17f95a..0dc6fda 100644
--- a/niepce-main/src/niepce/ui/dialogs/importlibrary.rs
+++ b/niepce-main/src/niepce/ui/dialogs/importlibrary.rs
@@ -28,7 +28,7 @@ use gtk::prelude::*;
 use gtk::{Assistant, Builder};
 use gtk_sys;
 
-use crate::libraryclient::LibraryClientWrapper;
+use npc_engine::libraryclient::LibraryClientWrapper;
 
 #[no_mangle]
 pub extern "C" fn dialog_import_library(
diff --git a/niepce-main/src/niepce/ui/dialogs/requestnewfolder.rs 
b/niepce-main/src/niepce/ui/dialogs/requestnewfolder.rs
index b4c4df4..71b5cd0 100644
--- a/niepce-main/src/niepce/ui/dialogs/requestnewfolder.rs
+++ b/niepce-main/src/niepce/ui/dialogs/requestnewfolder.rs
@@ -22,7 +22,7 @@ use glib::translate::*;
 use gtk::prelude::*;
 use gtk::{Dialog, Entry, Label};
 
-use crate::libraryclient::{ClientInterface, LibraryClientWrapper};
+use npc_engine::libraryclient::{ClientInterface, LibraryClientWrapper};
 
 /// # Safety
 /// Use raw pointers.
diff --git a/po/POTFILES.in b/po/POTFILES.in
index d116884..946ed10 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -1,6 +1,7 @@
 # List of source files containing translatable strings.
 # Please keep this file sorted alphabetically.
 camerawire/src/cwwindow.cpp
+crates/npc-engine/src/importer/lrimporter.rs
 data/org.gnome.Niepce.appdata.xml.in
 data/org.gnome.Niepce.desktop.in
 niepce-main/src/niepce/ui/dialogs/requestnewfolder.rs
diff --git a/src/Makefile.am b/src/Makefile.am
index 1b94dbc..9d7bf4b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -19,12 +19,18 @@ RUST_SOURCES = \
        @top_srcdir@/crates/npc-engine/src/db/libmetadata.rs \
        @top_srcdir@/crates/npc-engine/src/db/library.rs \
        @top_srcdir@/crates/npc-engine/src/db/props.rs \
+       @top_srcdir@/crates/npc-engine/src/importer.rs \
+       @top_srcdir@/crates/npc-engine/src/importer/libraryimporter.rs \
+       @top_srcdir@/crates/npc-engine/src/importer/lrimporter.rs \
        @top_srcdir@/crates/npc-engine/src/library.rs \
        @top_srcdir@/crates/npc-engine/src/library/commands.rs \
        @top_srcdir@/crates/npc-engine/src/library/notification.rs \
        @top_srcdir@/crates/npc-engine/src/library/op.rs \
        @top_srcdir@/crates/npc-engine/src/library/queriedcontent.rs \
        @top_srcdir@/crates/npc-engine/src/library/thumbnail_cache.rs \
+       @top_srcdir@/crates/npc-engine/src/libraryclient.rs \
+       @top_srcdir@/crates/npc-engine/src/libraryclient/clientimpl.rs \
+       @top_srcdir@/crates/npc-engine/src/libraryclient/clientinterface.rs \
        @top_srcdir@/crates/npc-engine/src/lib.rs \
        @top_srcdir@/crates/npc-fwk/Cargo.toml \
        @top_srcdir@/crates/npc-fwk/build.rs \
@@ -51,9 +57,6 @@ RUST_SOURCES = \
        @top_srcdir@/niepce-main/Cargo.toml \
        @top_srcdir@/niepce-main/examples/widget-test.rs \
        @top_srcdir@/niepce-main/src/lib.rs \
-       @top_srcdir@/niepce-main/src/libraryclient.rs \
-       @top_srcdir@/niepce-main/src/libraryclient/clientimpl.rs \
-       @top_srcdir@/niepce-main/src/libraryclient/clientinterface.rs \
        @top_srcdir@/niepce-main/src/niepce.rs \
        @top_srcdir@/niepce-main/src/niepce/ui.rs \
        @top_srcdir@/niepce-main/src/niepce/ui/imagetoolbar.rs \


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]