photoslibrary 0.1.0

Interact with Apple Photos.app library
Documentation
use anyhow::{Context, Result};
use futures::{Stream, StreamExt};
use std::path::{Path, PathBuf};

pub struct PhotosDb {
    library_path: PathBuf,
    conn: libsql::Connection,
}

impl PhotosDb {
    pub async fn new<P: AsRef<Path>>(library_path: P) -> Result<Self> {
        let library_path = library_path.as_ref().to_path_buf();
        let db_path = library_path.join("database").join("Photos.sqlite");
        let db = libsql::Builder::new_local(db_path)
            .build()
            .await
            .context("failed to open database")?;
        let conn = db.connect().context("failed to connect to database")?;
        Ok(Self { library_path, conn })
    }

    pub async fn visible_photos(&self) -> Result<impl Stream<Item = Result<Photo>>> {
        let mut stmt = self.conn.prepare("
            SELECT
                ZASSET.Z_PK,
                ZASSET.ZUUID,
                ZADDITIONALASSETATTRIBUTES.ZORIGINALFILENAME,
                ZASSET.ZDATECREATED,
                ZASSET.ZMODIFICATIONDATE,
                ZASSET.ZDIRECTORY,
                ZASSET.ZFILENAME,
                ZASSET.ZKIND,
                ZASSET.ZUNIFORMTYPEIDENTIFIER,
                ZASSET.ZKINDSUBTYPE,
                ZASSET.ZHEIGHT,
                ZASSET.ZWIDTH
            FROM ZASSET JOIN ZADDITIONALASSETATTRIBUTES ON ZADDITIONALASSETATTRIBUTES.ZASSET = ZASSET.Z_PK
            WHERE ZASSET.ZHIDDEN = 0 AND ZASSET.ZVISIBILITYSTATE = 0
            ORDER BY ZASSET.Z_PK;
        "
        ).await.context("failed to prepare statement")?;
        let rows = stmt.query(()).await.context("failed to execute query")?;
        Ok(rows.into_stream().map(|res| {
            let row = res.context("Error reading photo")?;
            Ok(Photo {
                pk: row.get(0)?,
                uuid: row.get(1)?,
            })
        }))
    }
}

pub struct Photo {
    pub pk: i64,
    pub uuid: String,
}