immich-tools/src/main.rs

102 lines
3.2 KiB
Rust

include!(concat!(env!("OUT_DIR"), "/codegen.rs"));
use crate::args::Commands;
use args::{PeopleCommands, ServerCommands};
use clap::Parser;
use color_eyre::eyre::{Result, WrapErr};
use color_eyre::Section;
use commands::missing_date_of_birth::missing_date_of_birth;
use commands::server_version::server_version;
use commands::sync_date_of_birth::sync_date_of_birth;
use config::Config;
use directories::ProjectDirs;
use figment::providers::{Env, Format, Serialized, Toml};
use figment::Figment;
use figment_file_provider_adapter::FileAdapter;
use log::*;
use reqwest::header;
mod args;
mod commands;
mod config;
mod utils;
#[tokio::main]
async fn main() -> Result<()> {
color_eyre::install()?;
pretty_env_logger::init();
let mut conf_extractor = Figment::new();
if let Some(project_dirs) = ProjectDirs::from("fr", "enoent", "Immich Tools") {
let config_file_path = project_dirs.config_dir().join("config.toml");
if config_file_path.exists() {
debug!("Reading configuration from {:?}", config_file_path);
conf_extractor =
conf_extractor.merge(FileAdapter::wrap(Toml::file_exact(config_file_path)));
}
} else {
warn!("Unable to determine configuration file path");
}
let args = args::Opts::parse();
let conf: Config = conf_extractor
.merge(FileAdapter::wrap(Env::prefixed("IMMICH_TOOLS_")))
.merge(Serialized::defaults(&args))
.extract()?;
let client = get_client(&conf.server_url, &conf.api_key)?;
validate_client_connection(&client).await?;
match &args.command {
Commands::People { people_command } => match people_command {
PeopleCommands::MissingDateOfBirths {} => missing_date_of_birth(&client).await,
PeopleCommands::SyncDateOfBirths { vcard: _ } => {
sync_date_of_birth(
&client,
&conf.people.sync_date_of_births.vcard,
args.dry_run,
)
.await
}
},
Commands::Server { server_command } => match server_command {
ServerCommands::Version {} => server_version(&client).await,
},
}
}
fn get_client(url: &str, api_key: &str) -> Result<Client> {
let mut headers = header::HeaderMap::new();
let mut auth_value = header::HeaderValue::from_str(api_key)?;
auth_value.set_sensitive(true);
headers.insert("x-api-key", auth_value);
Ok(Client::new_with_client(
url,
reqwest::Client::builder()
.default_headers(headers)
.build()
.unwrap(),
))
}
async fn validate_client_connection(client: &Client) -> Result<()> {
client
.validate_access_token()
.await
.wrap_err_with(|| "Unable to connect to Immich")
.with_suggestion(|| "The API key might be invalid")
.with_suggestion(|| "There server URL might be invalid, it should likely end in /api")
.with_note(|| format!("The provided server URL was {}", client.baseurl()))
.with_note(|| {
format!(
"The API version for this client is {}, make sure the server version is compatible",
client.api_version()
)
})?;
Ok(())
}