Add an assets list command
This commit is contained in:
		
							parent
							
								
									a8796b2728
								
							
						
					
					
						commit
						c026375ce1
					
				
					 5 changed files with 109 additions and 5 deletions
				
			
		
							
								
								
									
										19
									
								
								src/args.rs
									
										
									
									
									
								
							
							
						
						
									
										19
									
								
								src/args.rs
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -27,6 +27,14 @@ pub(crate) struct Opts {
 | 
			
		|||
 | 
			
		||||
#[derive(Serialize, Subcommand)]
 | 
			
		||||
pub(crate) enum Commands {
 | 
			
		||||
    /// Assets related commands
 | 
			
		||||
    #[serde(rename = "assets")]
 | 
			
		||||
    Assets {
 | 
			
		||||
        #[command(subcommand)]
 | 
			
		||||
        #[serde(flatten)]
 | 
			
		||||
        assets_command: AssetsCommands,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /// People related commands
 | 
			
		||||
    #[serde(rename = "people")]
 | 
			
		||||
    People {
 | 
			
		||||
| 
						 | 
				
			
			@ -43,6 +51,17 @@ pub(crate) enum Commands {
 | 
			
		|||
    },
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Serialize, Subcommand)]
 | 
			
		||||
pub(crate) enum AssetsCommands {
 | 
			
		||||
    /// List all assets
 | 
			
		||||
    #[serde(rename = "list")]
 | 
			
		||||
    List {
 | 
			
		||||
        /// List only offline assets
 | 
			
		||||
        #[arg(short, long, action)]
 | 
			
		||||
        offline: bool,
 | 
			
		||||
    },
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Serialize, Subcommand)]
 | 
			
		||||
pub(crate) enum PeopleCommands {
 | 
			
		||||
    /// Synchronises date of births from a vcard file
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										59
									
								
								src/commands/list_assets.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								src/commands/list_assets.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,59 @@
 | 
			
		|||
use crate::{
 | 
			
		||||
    utils::assets::{fetch_all_assets, AssetQuery},
 | 
			
		||||
    Client,
 | 
			
		||||
};
 | 
			
		||||
use color_eyre::eyre::Result;
 | 
			
		||||
use tabled::{
 | 
			
		||||
    settings::{
 | 
			
		||||
        object::{Columns, Object, Rows},
 | 
			
		||||
        Format, Style,
 | 
			
		||||
    },
 | 
			
		||||
    Table, Tabled,
 | 
			
		||||
};
 | 
			
		||||
#[derive(Tabled)]
 | 
			
		||||
struct Asset {
 | 
			
		||||
    #[tabled(rename = "Path")]
 | 
			
		||||
    original_file_path: String,
 | 
			
		||||
    #[tabled(rename = "Is offline")]
 | 
			
		||||
    is_offline: bool,
 | 
			
		||||
    #[tabled(rename = "Camera")]
 | 
			
		||||
    model: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub async fn list_assets(offline: bool, client: &Client) -> Result<()> {
 | 
			
		||||
    let query = AssetQuery {
 | 
			
		||||
        is_offline: if offline { Some(true) } else { None },
 | 
			
		||||
        with_exif: true,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let mut assets: Vec<_> = fetch_all_assets(query, client)
 | 
			
		||||
        .await?
 | 
			
		||||
        .into_iter()
 | 
			
		||||
        .map(|asset| Asset {
 | 
			
		||||
            is_offline: asset.is_offline,
 | 
			
		||||
            model: asset
 | 
			
		||||
                .exif_info
 | 
			
		||||
                .clone()
 | 
			
		||||
                .and_then(|exif| exif.model)
 | 
			
		||||
                .unwrap_or(String::from("(Unknown)")),
 | 
			
		||||
            original_file_path: asset.original_path,
 | 
			
		||||
        })
 | 
			
		||||
        .collect();
 | 
			
		||||
 | 
			
		||||
    assets.sort_by_key(|asset| asset.original_file_path.clone());
 | 
			
		||||
 | 
			
		||||
    println!(
 | 
			
		||||
        "{}",
 | 
			
		||||
        Table::new(assets).with(Style::rounded()).modify(
 | 
			
		||||
            Columns::single(1).not(Rows::first()),
 | 
			
		||||
            Format::content(|s| {
 | 
			
		||||
                match s {
 | 
			
		||||
                    "true" => "Yes".to_string(),
 | 
			
		||||
                    _ => "No".to_string(),
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
        )
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
pub mod list_assets;
 | 
			
		||||
pub mod missing_date_of_birth;
 | 
			
		||||
pub mod server_features;
 | 
			
		||||
pub mod server_version;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,10 +1,11 @@
 | 
			
		|||
include!(concat!(env!("OUT_DIR"), "/codegen.rs"));
 | 
			
		||||
 | 
			
		||||
use crate::args::Commands;
 | 
			
		||||
use args::{PeopleCommands, ServerCommands};
 | 
			
		||||
use args::{AssetsCommands, PeopleCommands, ServerCommands};
 | 
			
		||||
use clap::Parser;
 | 
			
		||||
use color_eyre::eyre::{Result, WrapErr};
 | 
			
		||||
use color_eyre::Section;
 | 
			
		||||
use commands::list_assets::list_assets;
 | 
			
		||||
use commands::missing_date_of_birth::missing_date_of_birth;
 | 
			
		||||
use commands::server_features::server_features;
 | 
			
		||||
use commands::server_version::server_version;
 | 
			
		||||
| 
						 | 
				
			
			@ -51,6 +52,9 @@ async fn main() -> Result<()> {
 | 
			
		|||
    validate_client_connection(&client).await?;
 | 
			
		||||
 | 
			
		||||
    match &args.command {
 | 
			
		||||
        Commands::Assets { assets_command } => match assets_command {
 | 
			
		||||
            AssetsCommands::List { offline } => list_assets(*offline, &client).await,
 | 
			
		||||
        },
 | 
			
		||||
        Commands::People { people_command } => match people_command {
 | 
			
		||||
            PeopleCommands::MissingDateOfBirths {} => missing_date_of_birth(&client).await,
 | 
			
		||||
            PeopleCommands::SyncDateOfBirths { vcard: _ } => {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,9 +2,26 @@ use crate::{
 | 
			
		|||
    types::{AssetResponseDto, MetadataSearchDto},
 | 
			
		||||
    Client,
 | 
			
		||||
};
 | 
			
		||||
use chrono::{TimeZone, Utc};
 | 
			
		||||
use color_eyre::eyre::Result;
 | 
			
		||||
use log::debug;
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Default)]
 | 
			
		||||
pub struct AssetQuery {
 | 
			
		||||
    pub is_offline: Option<bool>,
 | 
			
		||||
    pub with_exif: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub async fn fetch_all_assets(query: AssetQuery, client: &Client) -> Result<Vec<AssetResponseDto>> {
 | 
			
		||||
    debug!("Fetching assets with query {:?}", query);
 | 
			
		||||
 | 
			
		||||
    // is_offline is ignored, let's fetch trashed assets instead and filter them later
 | 
			
		||||
    let trashed_after = if query.is_offline == Some(true) {
 | 
			
		||||
        Some(Utc.with_ymd_and_hms(1970, 1, 1, 0, 0, 0).unwrap())
 | 
			
		||||
    } else {
 | 
			
		||||
        None
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
pub async fn fetch_all_assets(client: &Client) -> Result<Vec<AssetResponseDto>> {
 | 
			
		||||
    let mut all_assets = Vec::new();
 | 
			
		||||
    let mut page_number = None;
 | 
			
		||||
    let mut has_next_page = true;
 | 
			
		||||
| 
						 | 
				
			
			@ -26,7 +43,7 @@ pub async fn fetch_all_assets(client: &Client) -> Result<Vec<AssetResponseDto>>
 | 
			
		|||
                is_favorite: None,
 | 
			
		||||
                is_motion: None,
 | 
			
		||||
                is_not_in_album: None,
 | 
			
		||||
                is_offline: None,
 | 
			
		||||
                is_offline: query.is_offline,
 | 
			
		||||
                is_visible: None,
 | 
			
		||||
                lens_model: None,
 | 
			
		||||
                library_id: None,
 | 
			
		||||
| 
						 | 
				
			
			@ -43,14 +60,14 @@ pub async fn fetch_all_assets(client: &Client) -> Result<Vec<AssetResponseDto>>
 | 
			
		|||
                taken_after: None,
 | 
			
		||||
                taken_before: None,
 | 
			
		||||
                thumbnail_path: None,
 | 
			
		||||
                trashed_after: None,
 | 
			
		||||
                trashed_after,
 | 
			
		||||
                trashed_before: None,
 | 
			
		||||
                type_: None,
 | 
			
		||||
                updated_after: None,
 | 
			
		||||
                updated_before: None,
 | 
			
		||||
                with_archived: true,
 | 
			
		||||
                with_deleted: None,
 | 
			
		||||
                with_exif: None,
 | 
			
		||||
                with_exif: Some(query.with_exif),
 | 
			
		||||
                with_people: None,
 | 
			
		||||
                with_stacked: None,
 | 
			
		||||
            })
 | 
			
		||||
| 
						 | 
				
			
			@ -64,5 +81,9 @@ pub async fn fetch_all_assets(client: &Client) -> Result<Vec<AssetResponseDto>>
 | 
			
		|||
            .map(|page| page.parse::<f64>().unwrap());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if query.is_offline == Some(true) {
 | 
			
		||||
        all_assets.retain(|asset| asset.is_offline);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Ok(all_assets)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue