Add thumbnail endpoint with size options
This commit is contained in:
50
examples/thumbnail.rs
Normal file
50
examples/thumbnail.rs
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
//! Example: Download asset thumbnails
|
||||||
|
|
||||||
|
use immich_sdk::Client;
|
||||||
|
use immich_sdk::models::AssetMediaSize;
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
// Create a client
|
||||||
|
let client = Client::from_url("https://immich.example.com")?.with_api_key("your-api-key");
|
||||||
|
|
||||||
|
// Asset ID to download thumbnail for
|
||||||
|
let asset_id = "your-asset-id-here".parse()?;
|
||||||
|
|
||||||
|
// Download thumbnail (small size, default)
|
||||||
|
println!("Downloading thumbnail...");
|
||||||
|
let thumbnail = client
|
||||||
|
.assets()
|
||||||
|
.thumbnail(asset_id)
|
||||||
|
.size(AssetMediaSize::Thumbnail)
|
||||||
|
.execute()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
fs::write("/path/to/output/thumbnail.jpg", &thumbnail)?;
|
||||||
|
println!("Saved thumbnail: {} bytes", thumbnail.len());
|
||||||
|
|
||||||
|
// Download preview (medium size)
|
||||||
|
let preview = client
|
||||||
|
.assets()
|
||||||
|
.thumbnail(asset_id)
|
||||||
|
.size(AssetMediaSize::Preview)
|
||||||
|
.execute()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
fs::write("/path/to/output/preview.jpg", &preview)?;
|
||||||
|
println!("Saved preview: {} bytes", preview.len());
|
||||||
|
|
||||||
|
// Download fullsize
|
||||||
|
let fullsize = client
|
||||||
|
.assets()
|
||||||
|
.thumbnail(asset_id)
|
||||||
|
.size(AssetMediaSize::Fullsize)
|
||||||
|
.execute()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
fs::write("/path/to/output/fullsize.jpg", &fullsize)?;
|
||||||
|
println!("Saved fullsize: {} bytes", fullsize.len());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@ use std::path::Path;
|
|||||||
use crate::{
|
use crate::{
|
||||||
Client,
|
Client,
|
||||||
error::{ImmichError, Result},
|
error::{ImmichError, Result},
|
||||||
models::{AssetId, AssetResponse, AssetUploadResponse, DeleteAssetsRequest},
|
models::{AssetId, AssetMediaSize, AssetResponse, AssetUploadResponse, DeleteAssetsRequest},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// API for managing assets (photos and videos)
|
/// API for managing assets (photos and videos)
|
||||||
@@ -44,6 +44,11 @@ impl AssetsApi {
|
|||||||
pub fn download(&self, id: AssetId) -> DownloadAssetBuilder {
|
pub fn download(&self, id: AssetId) -> DownloadAssetBuilder {
|
||||||
DownloadAssetBuilder::new(self.client.clone(), id)
|
DownloadAssetBuilder::new(self.client.clone(), id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get asset thumbnail
|
||||||
|
pub fn thumbnail(&self, id: AssetId) -> ThumbnailBuilder {
|
||||||
|
ThumbnailBuilder::new(self.client.clone(), id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builder for listing assets
|
/// Builder for listing assets
|
||||||
@@ -299,3 +304,60 @@ impl DownloadAssetBuilder {
|
|||||||
Ok(bytes)
|
Ok(bytes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builder for getting asset thumbnail
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ThumbnailBuilder {
|
||||||
|
client: Client,
|
||||||
|
id: AssetId,
|
||||||
|
size: Option<AssetMediaSize>,
|
||||||
|
edited: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ThumbnailBuilder {
|
||||||
|
/// Create a new thumbnail builder
|
||||||
|
const fn new(client: Client, id: AssetId) -> Self {
|
||||||
|
Self {
|
||||||
|
client,
|
||||||
|
id,
|
||||||
|
size: None,
|
||||||
|
edited: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the thumbnail size
|
||||||
|
pub fn size(mut self, size: AssetMediaSize) -> Self {
|
||||||
|
self.size = Some(size);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the edited version if available
|
||||||
|
pub fn edited(mut self) -> Self {
|
||||||
|
self.edited = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Execute the request
|
||||||
|
pub async fn execute(self) -> Result<bytes::Bytes> {
|
||||||
|
let path = format!("/assets/{}/thumbnail", self.id);
|
||||||
|
let mut req = self.client.get(&path);
|
||||||
|
|
||||||
|
if let Some(ref size) = self.size {
|
||||||
|
let size_str = match size {
|
||||||
|
AssetMediaSize::Original => "original",
|
||||||
|
AssetMediaSize::Fullsize => "fullsize",
|
||||||
|
AssetMediaSize::Preview => "preview",
|
||||||
|
AssetMediaSize::Thumbnail => "thumbnail",
|
||||||
|
};
|
||||||
|
req = req.query(&[("size", size_str)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.edited {
|
||||||
|
req = req.query(&[("edited", "true")]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let response = self.client.execute(req.build()?).await?;
|
||||||
|
let bytes = response.bytes().await?;
|
||||||
|
Ok(bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -68,6 +68,20 @@ pub enum AssetVisibility {
|
|||||||
Locked,
|
Locked,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Asset media size for thumbnails
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
#[serde(rename_all = "lowercase")]
|
||||||
|
pub enum AssetMediaSize {
|
||||||
|
/// Original size
|
||||||
|
Original,
|
||||||
|
/// Full size
|
||||||
|
Fullsize,
|
||||||
|
/// Preview size
|
||||||
|
Preview,
|
||||||
|
/// Thumbnail size
|
||||||
|
Thumbnail,
|
||||||
|
}
|
||||||
|
|
||||||
/// EXIF information for an asset
|
/// EXIF information for an asset
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
|
|||||||
Reference in New Issue
Block a user