Merge branch 'dob-sync' into 'main'
Add a command to synchronise date of births See merge request kernald/immich-tools!2
This commit is contained in:
		
						commit
						dfce1f94ad
					
				
					 6 changed files with 392 additions and 5 deletions
				
			
		
							
								
								
									
										227
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										227
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							| 
						 | 
				
			
			@ -29,6 +29,15 @@ dependencies = [
 | 
			
		|||
 "zerocopy",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "aho-corasick"
 | 
			
		||||
version = "0.7.20"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "memchr",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "aho-corasick"
 | 
			
		||||
version = "1.1.3"
 | 
			
		||||
| 
						 | 
				
			
			@ -135,12 +144,24 @@ dependencies = [
 | 
			
		|||
 "windows-targets",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "base64"
 | 
			
		||||
version = "0.21.7"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "base64"
 | 
			
		||||
version = "0.22.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "beef"
 | 
			
		||||
version = "0.5.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "bitflags"
 | 
			
		||||
version = "1.3.2"
 | 
			
		||||
| 
						 | 
				
			
			@ -257,6 +278,15 @@ version = "0.8.7"
 | 
			
		|||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "deranged"
 | 
			
		||||
version = "0.3.11"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "powerfmt",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "dyn-clone"
 | 
			
		||||
version = "1.0.17"
 | 
			
		||||
| 
						 | 
				
			
			@ -272,6 +302,19 @@ dependencies = [
 | 
			
		|||
 "cfg-if",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "env_logger"
 | 
			
		||||
version = "0.10.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "humantime",
 | 
			
		||||
 "is-terminal",
 | 
			
		||||
 "log",
 | 
			
		||||
 "regex",
 | 
			
		||||
 "termcolor",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "equivalent"
 | 
			
		||||
version = "1.0.1"
 | 
			
		||||
| 
						 | 
				
			
			@ -477,6 +520,12 @@ version = "0.3.9"
 | 
			
		|||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "hermit-abi"
 | 
			
		||||
version = "0.4.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "http"
 | 
			
		||||
version = "1.1.0"
 | 
			
		||||
| 
						 | 
				
			
			@ -517,6 +566,12 @@ version = "1.9.5"
 | 
			
		|||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "humantime"
 | 
			
		||||
version = "2.1.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "hyper"
 | 
			
		||||
version = "1.5.0"
 | 
			
		||||
| 
						 | 
				
			
			@ -630,6 +685,8 @@ dependencies = [
 | 
			
		|||
 "chrono",
 | 
			
		||||
 "clap",
 | 
			
		||||
 "futures",
 | 
			
		||||
 "log",
 | 
			
		||||
 "pretty_env_logger",
 | 
			
		||||
 "prettyplease",
 | 
			
		||||
 "progenitor",
 | 
			
		||||
 "progenitor-client",
 | 
			
		||||
| 
						 | 
				
			
			@ -640,6 +697,7 @@ dependencies = [
 | 
			
		|||
 "syn",
 | 
			
		||||
 "tokio",
 | 
			
		||||
 "uuid",
 | 
			
		||||
 "vcard4",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
| 
						 | 
				
			
			@ -659,6 +717,17 @@ version = "2.10.1"
 | 
			
		|||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "is-terminal"
 | 
			
		||||
version = "0.4.13"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "hermit-abi 0.4.0",
 | 
			
		||||
 "libc",
 | 
			
		||||
 "windows-sys 0.52.0",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "is_terminal_polyfill"
 | 
			
		||||
version = "1.70.1"
 | 
			
		||||
| 
						 | 
				
			
			@ -714,6 +783,39 @@ version = "0.4.22"
 | 
			
		|||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "logos"
 | 
			
		||||
version = "0.14.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "1c6b6e02facda28ca5fb8dbe4b152496ba3b1bd5a4b40bb2b1b2d8ad74e0f39b"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "logos-derive",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "logos-codegen"
 | 
			
		||||
version = "0.14.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "b32eb6b5f26efacd015b000bfc562186472cd9b34bdba3f6b264e2a052676d10"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "beef",
 | 
			
		||||
 "fnv",
 | 
			
		||||
 "lazy_static",
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
 "quote",
 | 
			
		||||
 "regex-syntax",
 | 
			
		||||
 "syn",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "logos-derive"
 | 
			
		||||
version = "0.14.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "3e5d0c5463c911ef55624739fc353238b4e310f0144be1f875dc42fec6bfd5ec"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "logos-codegen",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "memchr"
 | 
			
		||||
version = "2.7.4"
 | 
			
		||||
| 
						 | 
				
			
			@ -741,7 +843,7 @@ version = "1.0.2"
 | 
			
		|||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "hermit-abi",
 | 
			
		||||
 "hermit-abi 0.3.9",
 | 
			
		||||
 "libc",
 | 
			
		||||
 "wasi",
 | 
			
		||||
 "windows-sys 0.52.0",
 | 
			
		||||
| 
						 | 
				
			
			@ -765,6 +867,12 @@ dependencies = [
 | 
			
		|||
 "tempfile",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "num-conv"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "num-traits"
 | 
			
		||||
version = "0.2.19"
 | 
			
		||||
| 
						 | 
				
			
			@ -891,6 +999,22 @@ version = "0.3.31"
 | 
			
		|||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "powerfmt"
 | 
			
		||||
version = "0.2.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "pretty_env_logger"
 | 
			
		||||
version = "0.5.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "865724d4dbe39d9f3dd3b52b88d859d66bcb2d6a0acfd5ea68a65fb66d4bdc1c"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "env_logger",
 | 
			
		||||
 "log",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "prettyplease"
 | 
			
		||||
version = "0.2.24"
 | 
			
		||||
| 
						 | 
				
			
			@ -1000,7 +1124,7 @@ version = "1.11.0"
 | 
			
		|||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "aho-corasick",
 | 
			
		||||
 "aho-corasick 1.1.3",
 | 
			
		||||
 "memchr",
 | 
			
		||||
 "regex-automata",
 | 
			
		||||
 "regex-syntax",
 | 
			
		||||
| 
						 | 
				
			
			@ -1012,7 +1136,7 @@ version = "0.4.8"
 | 
			
		|||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "aho-corasick",
 | 
			
		||||
 "aho-corasick 1.1.3",
 | 
			
		||||
 "memchr",
 | 
			
		||||
 "regex-syntax",
 | 
			
		||||
]
 | 
			
		||||
| 
						 | 
				
			
			@ -1039,7 +1163,7 @@ version = "0.12.8"
 | 
			
		|||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "base64",
 | 
			
		||||
 "base64 0.22.1",
 | 
			
		||||
 "bytes",
 | 
			
		||||
 "encoding_rs",
 | 
			
		||||
 "futures-core",
 | 
			
		||||
| 
						 | 
				
			
			@ -1422,6 +1546,15 @@ dependencies = [
 | 
			
		|||
 "windows-sys 0.59.0",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "termcolor"
 | 
			
		||||
version = "1.4.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "winapi-util",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "thiserror"
 | 
			
		||||
version = "1.0.65"
 | 
			
		||||
| 
						 | 
				
			
			@ -1442,6 +1575,37 @@ dependencies = [
 | 
			
		|||
 "syn",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "time"
 | 
			
		||||
version = "0.3.36"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "deranged",
 | 
			
		||||
 "itoa",
 | 
			
		||||
 "num-conv",
 | 
			
		||||
 "powerfmt",
 | 
			
		||||
 "serde",
 | 
			
		||||
 "time-core",
 | 
			
		||||
 "time-macros",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "time-core"
 | 
			
		||||
version = "0.1.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "time-macros"
 | 
			
		||||
version = "0.2.18"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "num-conv",
 | 
			
		||||
 "time-core",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "tinyvec"
 | 
			
		||||
version = "1.8.0"
 | 
			
		||||
| 
						 | 
				
			
			@ -1619,6 +1783,12 @@ dependencies = [
 | 
			
		|||
 "tinyvec",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "unicode-segmentation"
 | 
			
		||||
version = "1.12.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "unsafe-libyaml"
 | 
			
		||||
version = "0.2.11"
 | 
			
		||||
| 
						 | 
				
			
			@ -1631,6 +1801,16 @@ version = "0.9.0"
 | 
			
		|||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "uriparse"
 | 
			
		||||
version = "0.6.4"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "0200d0fc04d809396c2ad43f3c95da3582a2556eba8d453c1087f4120ee352ff"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "fnv",
 | 
			
		||||
 "lazy_static",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "url"
 | 
			
		||||
version = "2.5.2"
 | 
			
		||||
| 
						 | 
				
			
			@ -1658,6 +1838,22 @@ dependencies = [
 | 
			
		|||
 "serde",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "vcard4"
 | 
			
		||||
version = "0.5.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "92713aa20d2ffffdbc8e62cd3ebc14b448fc7d58b00f6976da8cef5419297101"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "aho-corasick 0.7.20",
 | 
			
		||||
 "base64 0.21.7",
 | 
			
		||||
 "logos",
 | 
			
		||||
 "thiserror",
 | 
			
		||||
 "time",
 | 
			
		||||
 "unicode-segmentation",
 | 
			
		||||
 "uriparse",
 | 
			
		||||
 "zeroize",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "vcpkg"
 | 
			
		||||
version = "0.2.15"
 | 
			
		||||
| 
						 | 
				
			
			@ -1775,6 +1971,15 @@ dependencies = [
 | 
			
		|||
 "wasm-bindgen",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "winapi-util"
 | 
			
		||||
version = "0.1.9"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "windows-sys 0.59.0",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "windows-core"
 | 
			
		||||
version = "0.52.0"
 | 
			
		||||
| 
						 | 
				
			
			@ -1921,3 +2126,17 @@ name = "zeroize"
 | 
			
		|||
version = "1.8.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "zeroize_derive",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "zeroize_derive"
 | 
			
		||||
version = "1.4.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
 "quote",
 | 
			
		||||
 "syn",
 | 
			
		||||
]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,12 +8,15 @@ anyhow = "1.0.91"
 | 
			
		|||
chrono = { version = "0.4.38", features = ["serde"] }
 | 
			
		||||
clap = { version = "4.5.20", features = ["derive"] }
 | 
			
		||||
futures = "0.3.31"
 | 
			
		||||
log = "0.4.22"
 | 
			
		||||
pretty_env_logger = "0.5.0"
 | 
			
		||||
progenitor-client = "0.8.0"
 | 
			
		||||
regress = "0.10.1"
 | 
			
		||||
reqwest = { version = "0.12.8", features = ["json", "stream"] }
 | 
			
		||||
serde = { version = "1.0.213", features = ["derive"] }
 | 
			
		||||
tokio = { version = "1.41.0", features = ["full"] }
 | 
			
		||||
uuid = { version = "1.11.0", features = ["serde", "v4"] }
 | 
			
		||||
vcard4 = "0.5.2"
 | 
			
		||||
 | 
			
		||||
[build-dependencies]
 | 
			
		||||
prettyplease = "0.2.24"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										19
									
								
								src/args.rs
									
										
									
									
									
								
							
							
						
						
									
										19
									
								
								src/args.rs
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,3 +1,5 @@
 | 
			
		|||
use std::path::PathBuf;
 | 
			
		||||
 | 
			
		||||
use clap::{command, Parser, Subcommand};
 | 
			
		||||
 | 
			
		||||
#[derive(Parser)]
 | 
			
		||||
| 
						 | 
				
			
			@ -9,12 +11,20 @@ pub(crate) struct Opts {
 | 
			
		|||
    #[arg(short, long)]
 | 
			
		||||
    pub api_key: String,
 | 
			
		||||
 | 
			
		||||
    #[arg(short, long)]
 | 
			
		||||
    pub dry_run: bool,
 | 
			
		||||
 | 
			
		||||
    #[command(subcommand)]
 | 
			
		||||
    pub command: Commands,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Subcommand)]
 | 
			
		||||
pub(crate) enum Commands {
 | 
			
		||||
    /// People related commands
 | 
			
		||||
    People {
 | 
			
		||||
        #[command(subcommand)]
 | 
			
		||||
        people_command: PeopleCommands,
 | 
			
		||||
    },
 | 
			
		||||
    /// Server related commands
 | 
			
		||||
    Server {
 | 
			
		||||
        #[command(subcommand)]
 | 
			
		||||
| 
						 | 
				
			
			@ -22,6 +32,15 @@ pub(crate) enum Commands {
 | 
			
		|||
    },
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Subcommand)]
 | 
			
		||||
pub(crate) enum PeopleCommands {
 | 
			
		||||
    /// Synchronises date of births from a vcard file
 | 
			
		||||
    SyncDateOfBirths {
 | 
			
		||||
        #[arg(short, long)]
 | 
			
		||||
        vcard_file: PathBuf,
 | 
			
		||||
    },
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Subcommand)]
 | 
			
		||||
pub(crate) enum ServerCommands {
 | 
			
		||||
    /// Fetches the version of the server
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1 +1,2 @@
 | 
			
		|||
pub mod server_version;
 | 
			
		||||
pub mod sync_date_of_birth;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										137
									
								
								src/commands/sync_date_of_birth.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								src/commands/sync_date_of_birth.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,137 @@
 | 
			
		|||
use std::{fs, path::PathBuf};
 | 
			
		||||
 | 
			
		||||
use anyhow::Result;
 | 
			
		||||
use chrono::{Datelike, NaiveDate};
 | 
			
		||||
use log::*;
 | 
			
		||||
use uuid::Uuid;
 | 
			
		||||
use vcard4::{
 | 
			
		||||
    parse_loose,
 | 
			
		||||
    property::{DateAndOrTime, DateTimeOrTextProperty},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    types::{PersonResponseDto, PersonUpdateDto},
 | 
			
		||||
    Client,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pub async fn sync_date_of_birth(
 | 
			
		||||
    client: &Client,
 | 
			
		||||
    vcard_file: &PathBuf,
 | 
			
		||||
    dry_run: bool,
 | 
			
		||||
) -> Result<()> {
 | 
			
		||||
    let server_contacts = fetch_all_contacts(client).await?;
 | 
			
		||||
 | 
			
		||||
    let filtered_contacts: Vec<_> = server_contacts
 | 
			
		||||
        .iter()
 | 
			
		||||
        .filter(|p| !p.name.is_empty())
 | 
			
		||||
        .collect();
 | 
			
		||||
 | 
			
		||||
    let contacts = fs::read_to_string(vcard_file)?;
 | 
			
		||||
    let cards = parse_loose(contacts)?;
 | 
			
		||||
 | 
			
		||||
    let cards_with_bday: Vec<_> = cards.iter().filter(|c| c.bday.is_some()).collect();
 | 
			
		||||
 | 
			
		||||
    info!(
 | 
			
		||||
        "{} vcards with date of births, {} persons with names fetched from Immich",
 | 
			
		||||
        cards_with_bday.len(),
 | 
			
		||||
        filtered_contacts.len()
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    let mut updated_dobs = 0;
 | 
			
		||||
 | 
			
		||||
    for card in cards_with_bday {
 | 
			
		||||
        let name = card.formatted_name.first().map(|text| text.value.clone());
 | 
			
		||||
        match name {
 | 
			
		||||
            Some(formatted_name) => {
 | 
			
		||||
                let contact = filtered_contacts.iter().find(|c| c.name == formatted_name);
 | 
			
		||||
                match contact {
 | 
			
		||||
                    Some(c) => match card.bday.as_ref().unwrap() {
 | 
			
		||||
                        DateTimeOrTextProperty::DateTime(dt) => {
 | 
			
		||||
                            let bday = vcard_date_to_naive_date(dt.value.first().unwrap().clone())?;
 | 
			
		||||
                            if c.birth_date.as_ref().map_or(false, |bdate| bday == *bdate) {
 | 
			
		||||
                                debug!(
 | 
			
		||||
                                    "{} already has the proper date of birth, skipping",
 | 
			
		||||
                                    formatted_name
 | 
			
		||||
                                );
 | 
			
		||||
                            } else if bday.year() > 0 {
 | 
			
		||||
                                update_person_bday(c, bday, client, dry_run).await?;
 | 
			
		||||
                                updated_dobs += 1;
 | 
			
		||||
                            } else {
 | 
			
		||||
                                debug!(
 | 
			
		||||
                                    "{} has an incomplete date of birth, skipping",
 | 
			
		||||
                                    formatted_name
 | 
			
		||||
                                );
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        DateTimeOrTextProperty::Text(_) => todo!(),
 | 
			
		||||
                    },
 | 
			
		||||
                    None => debug!("No Immich match for {}", formatted_name),
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            None => todo!(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    info!("Updated {} persons", updated_dobs);
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn vcard_date_to_naive_date(src: DateAndOrTime) -> Result<NaiveDate> {
 | 
			
		||||
    match src {
 | 
			
		||||
        DateAndOrTime::Date(date) => {
 | 
			
		||||
            Ok(
 | 
			
		||||
                NaiveDate::from_ymd_opt(date.year(), date.month() as u32, date.day().into())
 | 
			
		||||
                    .expect(&format!("Unable to parse {}", date)),
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
        DateAndOrTime::DateTime(datetime) => Ok(NaiveDate::from_ymd_opt(
 | 
			
		||||
            datetime.year(),
 | 
			
		||||
            datetime.month() as u32,
 | 
			
		||||
            datetime.day().into(),
 | 
			
		||||
        )
 | 
			
		||||
        .expect(&format!("Unable to parse {}", datetime))),
 | 
			
		||||
        DateAndOrTime::Time(_time) => todo!(),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async fn update_person_bday(
 | 
			
		||||
    person: &PersonResponseDto,
 | 
			
		||||
    bday: NaiveDate,
 | 
			
		||||
    client: &Client,
 | 
			
		||||
    dry_run: bool,
 | 
			
		||||
) -> Result<()> {
 | 
			
		||||
    let update = PersonUpdateDto {
 | 
			
		||||
        feature_face_asset_id: None,
 | 
			
		||||
        is_hidden: None,
 | 
			
		||||
        name: None,
 | 
			
		||||
        birth_date: Some(bday),
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    info!("Updating {}: {:?}", person.name, update);
 | 
			
		||||
 | 
			
		||||
    if !dry_run {
 | 
			
		||||
        client
 | 
			
		||||
            .update_person(&Uuid::parse_str(&person.id)?, &update)
 | 
			
		||||
            .await?;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async fn fetch_all_contacts(client: &Client) -> Result<Vec<PersonResponseDto>> {
 | 
			
		||||
    let mut all_people = Vec::new();
 | 
			
		||||
    let mut page_number = 1;
 | 
			
		||||
    let mut has_next_page = true;
 | 
			
		||||
 | 
			
		||||
    while has_next_page {
 | 
			
		||||
        let fetched = client
 | 
			
		||||
            .get_all_people(Some(page_number.into()), None, Some(true))
 | 
			
		||||
            .await?;
 | 
			
		||||
        all_people.extend(fetched.people.clone());
 | 
			
		||||
        has_next_page = fetched.has_next_page.expect("Missing has_next_page");
 | 
			
		||||
        page_number += 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Ok(all_people)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										10
									
								
								src/main.rs
									
										
									
									
									
								
							
							
						
						
									
										10
									
								
								src/main.rs
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -2,9 +2,10 @@ include!(concat!(env!("OUT_DIR"), "/codegen.rs"));
 | 
			
		|||
 | 
			
		||||
use crate::args::Commands;
 | 
			
		||||
use anyhow::Result;
 | 
			
		||||
use args::ServerCommands;
 | 
			
		||||
use args::{PeopleCommands, ServerCommands};
 | 
			
		||||
use clap::Parser;
 | 
			
		||||
use commands::server_version::server_version;
 | 
			
		||||
use commands::sync_date_of_birth::sync_date_of_birth;
 | 
			
		||||
use reqwest::header;
 | 
			
		||||
 | 
			
		||||
mod args;
 | 
			
		||||
| 
						 | 
				
			
			@ -12,11 +13,18 @@ mod commands;
 | 
			
		|||
 | 
			
		||||
#[tokio::main]
 | 
			
		||||
async fn main() {
 | 
			
		||||
    pretty_env_logger::init();
 | 
			
		||||
 | 
			
		||||
    let args = args::Opts::parse();
 | 
			
		||||
 | 
			
		||||
    let client = get_client(&args.server_url, &args.api_key).unwrap();
 | 
			
		||||
 | 
			
		||||
    let res = match &args.command {
 | 
			
		||||
        Commands::People { people_command } => match people_command {
 | 
			
		||||
            PeopleCommands::SyncDateOfBirths { vcard_file } => {
 | 
			
		||||
                sync_date_of_birth(&client, vcard_file, args.dry_run).await
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        Commands::Server { server_command } => match server_command {
 | 
			
		||||
            ServerCommands::Version {} => server_version(&client).await,
 | 
			
		||||
        },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue