Add a album auto-create command #29
					 14 changed files with 323 additions and 2 deletions
				
			
		
							
								
								
									
										10
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										10
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							| 
						 | 
				
			
			@ -1312,6 +1312,7 @@ dependencies = [
 | 
			
		|||
 "figment_file_provider_adapter",
 | 
			
		||||
 "httpmock",
 | 
			
		||||
 "log",
 | 
			
		||||
 "multimap",
 | 
			
		||||
 "openapiv3",
 | 
			
		||||
 "pretty_env_logger",
 | 
			
		||||
 "prettyplease",
 | 
			
		||||
| 
						 | 
				
			
			@ -1559,6 +1560,15 @@ dependencies = [
 | 
			
		|||
 "windows-sys 0.52.0",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "multimap"
 | 
			
		||||
version = "0.10.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "serde",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "native-tls"
 | 
			
		||||
version = "0.2.11"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,6 +22,7 @@ directories = "5.0.1"
 | 
			
		|||
figment = { version = "0.10.19", features = ["env", "toml"] }
 | 
			
		||||
figment_file_provider_adapter = "0.1.1"
 | 
			
		||||
log = "0.4.22"
 | 
			
		||||
multimap = "0.10.0"
 | 
			
		||||
pretty_env_logger = "0.5.0"
 | 
			
		||||
progenitor-client = "0.8.0"
 | 
			
		||||
readonly = "0.2.12"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										58
									
								
								src/actions/add_assets_to_album.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/actions/add_assets_to_album.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,58 @@
 | 
			
		|||
use color_eyre::eyre::Result;
 | 
			
		||||
use log::info;
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    context::Context,
 | 
			
		||||
    models::{album::Album, asset::Asset},
 | 
			
		||||
    types::BulkIdsDto,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
use super::action::Action;
 | 
			
		||||
 | 
			
		||||
pub struct AddAssetsToAlbum {
 | 
			
		||||
    album: Album,
 | 
			
		||||
    assets: Vec<Asset>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct AddAssetsToAlbumArgs {
 | 
			
		||||
    pub album: Album,
 | 
			
		||||
    pub assets: Vec<Asset>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Action for AddAssetsToAlbum {
 | 
			
		||||
    type Input = AddAssetsToAlbumArgs;
 | 
			
		||||
    type Output = ();
 | 
			
		||||
 | 
			
		||||
    fn new(input: Self::Input) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            album: input.album,
 | 
			
		||||
            assets: input.assets,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn describe(&self) -> String {
 | 
			
		||||
        format!(
 | 
			
		||||
            "Adding {} assets to album {}",
 | 
			
		||||
            self.assets.len(),
 | 
			
		||||
            self.album.name,
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn execute(&self, ctx: &Context) -> Result<Self::Output> {
 | 
			
		||||
        info!("{}", self.describe());
 | 
			
		||||
 | 
			
		||||
        if !ctx.dry_run {
 | 
			
		||||
            ctx.client
 | 
			
		||||
                .add_assets_to_album(
 | 
			
		||||
                    &self.album.id,
 | 
			
		||||
                    None,
 | 
			
		||||
                    &BulkIdsDto {
 | 
			
		||||
                        ids: self.assets.iter().map(|asset| asset.id).collect(),
 | 
			
		||||
                    },
 | 
			
		||||
                )
 | 
			
		||||
                .await?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										68
									
								
								src/actions/create_album.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								src/actions/create_album.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,68 @@
 | 
			
		|||
use chrono::Utc;
 | 
			
		||||
use color_eyre::eyre::Result;
 | 
			
		||||
use log::info;
 | 
			
		||||
use uuid::Uuid;
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    context::Context,
 | 
			
		||||
    models::{album::Album, asset::Asset},
 | 
			
		||||
    types::CreateAlbumDto,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
use super::action::Action;
 | 
			
		||||
 | 
			
		||||
pub struct CreateAlbum {
 | 
			
		||||
    name: String,
 | 
			
		||||
    assets: Vec<Asset>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Default)]
 | 
			
		||||
pub struct CreateAlbumArgs {
 | 
			
		||||
    pub name: String,
 | 
			
		||||
    pub assets: Vec<Asset>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Action for CreateAlbum {
 | 
			
		||||
    type Input = CreateAlbumArgs;
 | 
			
		||||
    type Output = Album;
 | 
			
		||||
 | 
			
		||||
    fn new(input: Self::Input) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            name: input.name,
 | 
			
		||||
            assets: input.assets,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn describe(&self) -> String {
 | 
			
		||||
        format!(
 | 
			
		||||
            "Creating album {} with {} assets",
 | 
			
		||||
            self.name,
 | 
			
		||||
            self.assets.len()
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn execute(&self, ctx: &Context) -> Result<Self::Output> {
 | 
			
		||||
        info!("{}", self.describe());
 | 
			
		||||
 | 
			
		||||
        if !ctx.dry_run {
 | 
			
		||||
            Ok(ctx
 | 
			
		||||
                .client
 | 
			
		||||
                .create_album(&CreateAlbumDto {
 | 
			
		||||
                    album_name: self.name.clone(),
 | 
			
		||||
                    asset_ids: self.assets.iter().map(|asset| asset.id).collect(),
 | 
			
		||||
                    album_users: vec![],
 | 
			
		||||
                    description: None,
 | 
			
		||||
                })
 | 
			
		||||
                .await?
 | 
			
		||||
                .clone()
 | 
			
		||||
                .into())
 | 
			
		||||
        } else {
 | 
			
		||||
            Ok(Album {
 | 
			
		||||
                id: Uuid::new_v4(),
 | 
			
		||||
                name: self.name.clone(),
 | 
			
		||||
                assets_count: self.assets.len() as u32,
 | 
			
		||||
                updated_at: Utc::now(),
 | 
			
		||||
            })
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										42
									
								
								src/actions/fetch_library_assets.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/actions/fetch_library_assets.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,42 @@
 | 
			
		|||
use color_eyre::eyre::Result;
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    context::Context,
 | 
			
		||||
    models::{asset::Asset, library::Library},
 | 
			
		||||
    utils::assets::{fetch_all_assets, AssetQuery},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
use super::action::Action;
 | 
			
		||||
 | 
			
		||||
pub struct FetchLibraryAssets {
 | 
			
		||||
    library: Library,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Action for FetchLibraryAssets {
 | 
			
		||||
    type Input = Library;
 | 
			
		||||
    type Output = Vec<Asset>;
 | 
			
		||||
 | 
			
		||||
    fn new(input: Self::Input) -> Self {
 | 
			
		||||
        Self { library: input }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn describe(&self) -> String {
 | 
			
		||||
        // TODO: derive Display for Library and use this here
 | 
			
		||||
        format!("Fetching all assets for library {}", self.library.name)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn execute(&self, ctx: &Context) -> Result<Self::Output> {
 | 
			
		||||
        let query = AssetQuery {
 | 
			
		||||
            library: Some(self.library.clone()),
 | 
			
		||||
            ..Default::default()
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let assets: Vec<_> = fetch_all_assets(query, &ctx.client)
 | 
			
		||||
            .await?
 | 
			
		||||
            .into_iter()
 | 
			
		||||
            .map(Asset::from)
 | 
			
		||||
            .collect();
 | 
			
		||||
 | 
			
		||||
        Ok(assets)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,9 +1,12 @@
 | 
			
		|||
pub mod action;
 | 
			
		||||
pub mod add_assets_to_album;
 | 
			
		||||
pub mod confirm;
 | 
			
		||||
pub mod create_album;
 | 
			
		||||
pub mod delete_album;
 | 
			
		||||
pub mod fetch_album_assets;
 | 
			
		||||
pub mod fetch_all_albums;
 | 
			
		||||
pub mod fetch_all_libraries;
 | 
			
		||||
pub mod fetch_all_persons;
 | 
			
		||||
pub mod fetch_library_assets;
 | 
			
		||||
pub mod scan_library;
 | 
			
		||||
pub mod update_person_date_of_birth;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -78,6 +78,13 @@ pub(crate) enum Commands {
 | 
			
		|||
 | 
			
		||||
#[derive(Serialize, Subcommand)]
 | 
			
		||||
pub(crate) enum AlbumsCommands {
 | 
			
		||||
    /// Create albums automatically from external libaries folder structure
 | 
			
		||||
    #[serde(rename = "auto-create")]
 | 
			
		||||
    AutoCreate {
 | 
			
		||||
        /// String to use when composing album names from nested folder structures
 | 
			
		||||
        #[arg(long, default_value = " / ")]
 | 
			
		||||
        album_name_separator: String,
 | 
			
		||||
    },
 | 
			
		||||
    /// Delete all albums
 | 
			
		||||
    #[serde(rename = "delete")]
 | 
			
		||||
    Delete {},
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										118
									
								
								src/commands/auto_create_albums.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								src/commands/auto_create_albums.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,118 @@
 | 
			
		|||
use std::path::{Path, PathBuf};
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    actions::{
 | 
			
		||||
        action::Action,
 | 
			
		||||
        add_assets_to_album::{AddAssetsToAlbum, AddAssetsToAlbumArgs},
 | 
			
		||||
        create_album::{CreateAlbum, CreateAlbumArgs},
 | 
			
		||||
        fetch_all_albums::FetchAllAlbums,
 | 
			
		||||
        fetch_all_libraries::FetchAllLibraries,
 | 
			
		||||
        fetch_library_assets::FetchLibraryAssets,
 | 
			
		||||
    },
 | 
			
		||||
    context::Context,
 | 
			
		||||
    models::{asset::Asset, library::Library},
 | 
			
		||||
};
 | 
			
		||||
use color_eyre::eyre::Result;
 | 
			
		||||
use log::*;
 | 
			
		||||
use multimap::MultiMap;
 | 
			
		||||
 | 
			
		||||
pub async fn auto_create_albums(ctx: Context, separator: String) -> Result<()> {
 | 
			
		||||
    let albums = FetchAllAlbums::new(()).execute(&ctx).await?;
 | 
			
		||||
    let libraries = FetchAllLibraries::new(()).execute(&ctx).await?;
 | 
			
		||||
    let mut assets: Vec<Asset> = vec![];
 | 
			
		||||
 | 
			
		||||
    for library in &libraries {
 | 
			
		||||
        assets.extend(
 | 
			
		||||
            FetchLibraryAssets::new(library.clone())
 | 
			
		||||
                .execute(&ctx)
 | 
			
		||||
                .await?
 | 
			
		||||
                .drain(0..),
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let mut sorted_assets = MultiMap::new();
 | 
			
		||||
 | 
			
		||||
    for asset in &assets {
 | 
			
		||||
        let path = extract_path(asset, &libraries);
 | 
			
		||||
        if let Some(path) = path {
 | 
			
		||||
            let asset_albums = extract_album_names(path, separator.clone());
 | 
			
		||||
            for album in asset_albums {
 | 
			
		||||
                sorted_assets.insert(album, asset.clone());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    debug!("Generated albums: {:?}", sorted_assets.keys());
 | 
			
		||||
 | 
			
		||||
    let missing_albums: Vec<_> = sorted_assets
 | 
			
		||||
        .keys()
 | 
			
		||||
        .filter(|k| !albums.iter().any(|album| album.name == **k))
 | 
			
		||||
        .cloned()
 | 
			
		||||
        .collect();
 | 
			
		||||
 | 
			
		||||
    info!("Creating missing albums: {:?}", missing_albums);
 | 
			
		||||
 | 
			
		||||
    for missing_album in &missing_albums {
 | 
			
		||||
        let assets = sorted_assets
 | 
			
		||||
            .remove(&missing_album.to_string())
 | 
			
		||||
            .unwrap_or(vec![]);
 | 
			
		||||
        CreateAlbum::new(CreateAlbumArgs {
 | 
			
		||||
            name: missing_album.to_string(),
 | 
			
		||||
            assets,
 | 
			
		||||
        })
 | 
			
		||||
        .execute(&ctx)
 | 
			
		||||
        .await?;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (album, assets) in sorted_assets {
 | 
			
		||||
        let existing_album = albums
 | 
			
		||||
            .iter()
 | 
			
		||||
            .find(|existing_album| existing_album.name == album);
 | 
			
		||||
 | 
			
		||||
        // Albums not present in albums were created just above with all the assets, so it's fine
 | 
			
		||||
        // to skip. On the other hand, Immich won't re-add the same asset multiple times to the
 | 
			
		||||
        // same album, so it's safe to re-add.
 | 
			
		||||
        if let Some(existing_album) = existing_album {
 | 
			
		||||
            info!("Adding {} assets to {}", assets.len(), album);
 | 
			
		||||
            AddAssetsToAlbum::new(AddAssetsToAlbumArgs {
 | 
			
		||||
                album: existing_album.clone(),
 | 
			
		||||
                assets,
 | 
			
		||||
            })
 | 
			
		||||
            .execute(&ctx)
 | 
			
		||||
            .await?;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn extract_path(asset: &Asset, libraries: &[Library]) -> Option<PathBuf> {
 | 
			
		||||
    for library in libraries {
 | 
			
		||||
        for import_path in &library.import_paths {
 | 
			
		||||
            if asset.original_path.starts_with(import_path) {
 | 
			
		||||
                return asset
 | 
			
		||||
                    .original_path
 | 
			
		||||
                    .strip_prefix(import_path)
 | 
			
		||||
                    .ok()
 | 
			
		||||
                    .and_then(Path::parent)
 | 
			
		||||
                    .map(Path::to_path_buf);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    None
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn extract_album_names(folder_path: PathBuf, separator: String) -> Vec<String> {
 | 
			
		||||
    let mut components = vec![];
 | 
			
		||||
    let mut current_component = String::new();
 | 
			
		||||
 | 
			
		||||
    for component in folder_path.components() {
 | 
			
		||||
        let component_str = component.as_os_str().to_str().unwrap();
 | 
			
		||||
        current_component += component_str;
 | 
			
		||||
        components.push(current_component.clone());
 | 
			
		||||
        current_component += &separator;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    components
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -24,6 +24,7 @@ pub async fn list_assets(ctx: Context, offline: bool) -> Result<()> {
 | 
			
		|||
    let query = AssetQuery {
 | 
			
		||||
        is_offline: if offline { Some(true) } else { None },
 | 
			
		||||
        with_exif: true,
 | 
			
		||||
        ..Default::default()
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let mut assets: Vec<_> = fetch_all_assets(query, &ctx.client)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
pub mod auto_create_albums;
 | 
			
		||||
pub mod delete_albums;
 | 
			
		||||
pub mod delete_assets;
 | 
			
		||||
pub mod list_albums;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,6 +13,7 @@ use args::{AlbumsCommands, AssetsCommands, LibrariesCommands, PeopleCommands, Se
 | 
			
		|||
use clap::Parser;
 | 
			
		||||
use color_eyre::eyre::{Result, WrapErr};
 | 
			
		||||
use color_eyre::Section;
 | 
			
		||||
use commands::auto_create_albums::auto_create_albums;
 | 
			
		||||
use commands::delete_albums::delete_albums;
 | 
			
		||||
use commands::delete_assets::delete_assets;
 | 
			
		||||
use commands::list_albums::list_albums;
 | 
			
		||||
| 
						 | 
				
			
			@ -79,6 +80,9 @@ async fn main() -> Result<()> {
 | 
			
		|||
 | 
			
		||||
    match &args.command {
 | 
			
		||||
        Commands::Albums { albums_command } => match albums_command {
 | 
			
		||||
            AlbumsCommands::AutoCreate {
 | 
			
		||||
                album_name_separator,
 | 
			
		||||
            } => auto_create_albums(ctx, album_name_separator.to_string()).await,
 | 
			
		||||
            AlbumsCommands::Delete {} => delete_albums(ctx).await,
 | 
			
		||||
            AlbumsCommands::List {} => list_albums(ctx).await,
 | 
			
		||||
        },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
use std::path::PathBuf;
 | 
			
		||||
use uuid::Uuid;
 | 
			
		||||
 | 
			
		||||
use crate::types::AssetResponseDto;
 | 
			
		||||
| 
						 | 
				
			
			@ -5,12 +6,14 @@ use crate::types::AssetResponseDto;
 | 
			
		|||
#[derive(Debug, Clone)]
 | 
			
		||||
pub struct Asset {
 | 
			
		||||
    pub id: Uuid,
 | 
			
		||||
    pub original_path: PathBuf,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<AssetResponseDto> for Asset {
 | 
			
		||||
    fn from(value: AssetResponseDto) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            id: Uuid::parse_str(&value.id).expect("Unable to parse an asset's UUID"),
 | 
			
		||||
            original_path: PathBuf::from(value.original_path),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,6 +10,7 @@ pub struct Library {
 | 
			
		|||
    pub asset_count: i64,
 | 
			
		||||
    pub updated_at: DateTime<Utc>,
 | 
			
		||||
    pub refreshed_at: Option<DateTime<Utc>>,
 | 
			
		||||
    pub import_paths: Vec<String>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<LibraryResponseDto> for Library {
 | 
			
		||||
| 
						 | 
				
			
			@ -20,6 +21,7 @@ impl From<LibraryResponseDto> for Library {
 | 
			
		|||
            asset_count: value.asset_count,
 | 
			
		||||
            updated_at: value.updated_at,
 | 
			
		||||
            refreshed_at: value.refreshed_at,
 | 
			
		||||
            import_paths: value.import_paths,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -38,7 +40,7 @@ mod tests {
 | 
			
		|||
            name: String::from("Christmas photos"),
 | 
			
		||||
            asset_count: 1246,
 | 
			
		||||
            exclusion_patterns: vec![],
 | 
			
		||||
            import_paths: vec![],
 | 
			
		||||
            import_paths: vec![String::from("/foo"), String::from("/mnt/bar")],
 | 
			
		||||
            owner_id: String::from("abc123"),
 | 
			
		||||
            updated_at: DateTime::<Utc>::from_str("2024-11-17T12:55:12Z").unwrap(),
 | 
			
		||||
            created_at: DateTime::<Utc>::from_str("2023-10-17T12:55:12Z").unwrap(),
 | 
			
		||||
| 
						 | 
				
			
			@ -61,6 +63,7 @@ mod tests {
 | 
			
		|||
            library.refreshed_at,
 | 
			
		||||
            Some(DateTime::<Utc>::from_str("2024-11-17T12:53:12Z").unwrap())
 | 
			
		||||
        );
 | 
			
		||||
        assert_eq!(library.import_paths, vec!["/foo", "/mnt/bar"]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
use crate::{
 | 
			
		||||
    models::library::Library,
 | 
			
		||||
    types::{AssetResponseDto, MetadataSearchDto},
 | 
			
		||||
    Client,
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -8,6 +9,7 @@ use log::debug;
 | 
			
		|||
 | 
			
		||||
#[derive(Debug, Default)]
 | 
			
		||||
pub struct AssetQuery {
 | 
			
		||||
    pub library: Option<Library>,
 | 
			
		||||
    pub is_offline: Option<bool>,
 | 
			
		||||
    pub with_exif: bool,
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -46,7 +48,7 @@ pub async fn fetch_all_assets(query: AssetQuery, client: &Client) -> Result<Vec<
 | 
			
		|||
                is_offline: query.is_offline,
 | 
			
		||||
                is_visible: None,
 | 
			
		||||
                lens_model: None,
 | 
			
		||||
                library_id: None,
 | 
			
		||||
                library_id: query.library.clone().map(|library| library.id),
 | 
			
		||||
                make: None,
 | 
			
		||||
                model: None,
 | 
			
		||||
                order: None,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue