Skip to content

Commit

Permalink
Add option for export to create the target folder
Browse files Browse the repository at this point in the history
  • Loading branch information
Caleb9 committed May 4, 2024
1 parent e3a9c56 commit 4330e92
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 12 deletions.
8 changes: 4 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,11 @@ pub enum Command {
/// Album name; can be a person name in "People" auto-album
album_name: String,

/// Folder name in user's Personal Space (must exist)
/// Create target folder if it does not exist in Personal Space
#[arg(long)]
create: bool,

/// Folder name in user's Personal Space
folder_path: String,
},

Expand Down
25 changes: 20 additions & 5 deletions src/commands/export/api_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ use syno_api::foto::background_task::file::dto::TaskInfo;
use syno_api::foto::{self, browse::folder::dto::Folder};
use syno_api::foto_team;

#[derive(Debug, Deserialize)]
struct FolderContainer {
folder: Folder,
}

impl<'a, C: ApiClient> SessionClient<'a, C> {
pub async fn get_folder_by_name(&self, name: &str) -> Result<Folder> {
#[derive(Debug, Deserialize)]
struct FolderContainer {
folder: Folder,
}

let folder: FolderContainer = self
.client
.get(
Expand All @@ -26,6 +26,21 @@ impl<'a, C: ApiClient> SessionClient<'a, C> {
Ok(folder.folder)
}

pub async fn create_folder(&self, name: &str, parent_id: u32) -> Result<Folder> {
let folder: FolderContainer = self
.client
.post(
self.dsm_url.clone(),
ApiParams::new(foto::browse::folder::API, "create", 1),
&[
("name", name),
("target_id", parent_id.to_string().as_str()),
],
)
.await?;
Ok(folder.folder)
}

pub async fn copy_photos(
&self,
photo_ids: &[u32],
Expand Down
38 changes: 37 additions & 1 deletion src/commands/export/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ mod api_client;
pub async fn handle<C: HttpClient, I: Io>(
album_name: &str,
target_folder_path: &str,
create_folder: bool,
conf: &Conf,
client: &C,
io: &mut I,
Expand All @@ -37,14 +38,17 @@ pub async fn handle<C: HttpClient, I: Io>(
}

let folder_path = format!("/{}", target_folder_path.trim().trim_matches('/'));
log::info!("Target folder: {folder_path}");
log::info!("target folder: {folder_path}");
let folder_future = client.get_folder_by_name(folder_path.as_str());

let find_album_future = find_album(album_name, &user_settings, &client);

let folder = match folder_future.await {
Ok(folder) => folder,
Err(error) => match error.downcast::<DsmError>()? {
DsmError::Photo(PhotoError::NoAccessOrNotFound) if create_folder => {
create_folder_path(folder_path.as_str(), &client).await?
}
DsmError::Photo(PhotoError::NoAccessOrNotFound) => {
bail!("folder '{target_folder_path}' does not exist in Personal Space")
}
Expand All @@ -64,6 +68,38 @@ pub async fn handle<C: HttpClient, I: Io>(
}
}

async fn create_folder_path<C: ApiClient>(
folder_path: &str,
client: &SessionClient<'_, C>,
) -> Result<Folder> {
let path_segments: Vec<_> = folder_path.split('/').filter(|s| !s.is_empty()).collect();
if path_segments.iter().any(|s| s.trim().is_empty()) {
bail!("{folder_path} is not valid folder path");
}
let mut result_folder = client.get_folder_by_name("/").await?;
let mut path_so_far = String::new();
let mut exists = true;
for segment in path_segments {
path_so_far.push('/');
path_so_far.push_str(segment);
if exists {
let folder_result = client.get_folder_by_name(path_so_far.as_str()).await;
match folder_result {
Ok(folder) => result_folder = folder,
Err(error) => match error.downcast::<DsmError>()? {
DsmError::Photo(PhotoError::NoAccessOrNotFound) => exists = false,
other => bail!(other),
},
}
}
if !exists {
result_folder = client.create_folder(segment, result_folder.id).await?;
log::info!("created {path_so_far} folder")
}
}
Ok(result_folder)
}

async fn export<C: ApiClient, I: Io>(
(album, target_folder, user_settings): (Album, Folder, UserSettings),
client: &SessionClient<'_, C>,
Expand Down
2 changes: 1 addition & 1 deletion src/commands/login/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ fn unwrap_or_read_dsm_url<I: Io>(url: Option<Url>, conf: &Conf, io: &mut I) -> R
dsm_url
.set_port(Some(port))
.expect("DSM URL address should be valid");
log::info!("Using DSM address: {dsm_url}")
log::info!("using DSM address: {dsm_url}")
}
Ok(dsm_url)
}
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,13 @@ pub async fn run<I: Io, C: HttpClient, S: CookieStore, F: Fs>(
}
Command::Export {
album_name,
create,
folder_path,
} => {
export::handle(
album_name.as_str(),
folder_path.as_str(),
create,
&conf,
&client.client,
io,
Expand Down

0 comments on commit 4330e92

Please sign in to comment.