forked from wathiede/photosync
Compare commits
1 Commits
7a6394c7f8
...
7a31a73e60
| Author | SHA1 | Date | |
|---|---|---|---|
| 7a31a73e60 |
92
src/main.rs
92
src/main.rs
@ -2,8 +2,8 @@ use std::error::Error;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use google_api_auth;
|
use google_api_auth;
|
||||||
use google_photoslibrary1;
|
use google_photoslibrary1 as photos;
|
||||||
use google_photoslibrary1::schemas::SearchMediaItemsRequest;
|
use photos::schemas::{MediaItem, SearchMediaItemsRequest};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
use yup_oauth2::{Authenticator, InstalledFlow};
|
use yup_oauth2::{Authenticator, InstalledFlow};
|
||||||
@ -43,7 +43,7 @@ struct Opt {
|
|||||||
fn new_client(
|
fn new_client(
|
||||||
credentials: &PathBuf,
|
credentials: &PathBuf,
|
||||||
token_cache: &PathBuf,
|
token_cache: &PathBuf,
|
||||||
) -> Result<google_photoslibrary1::Client, Box<dyn Error>> {
|
) -> Result<photos::Client, Box<dyn Error>> {
|
||||||
let secret = yup_oauth2::read_application_secret(credentials)?;
|
let secret = yup_oauth2::read_application_secret(credentials)?;
|
||||||
|
|
||||||
// Create an authenticator that uses an InstalledFlow to authenticate. The
|
// Create an authenticator that uses an InstalledFlow to authenticate. The
|
||||||
@ -58,53 +58,87 @@ fn new_client(
|
|||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let scopes = vec!["https://www.googleapis.com/auth/photoslibrary.readonly".to_string()];
|
let scopes = vec!["https://www.googleapis.com/auth/photoslibrary.readonly"];
|
||||||
|
|
||||||
let auth = google_api_auth::yup_oauth2::from_authenticator(auth, scopes);
|
let auth = google_api_auth::yup_oauth2::from_authenticator(auth, scopes);
|
||||||
|
|
||||||
Ok(google_photoslibrary1::Client::new(auth))
|
Ok(photos::Client::new(auth))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn search_media_items(
|
struct SearchIter<'a> {
|
||||||
client: google_photoslibrary1::Client,
|
client: &'a photos::Client,
|
||||||
album_id: String,
|
items: ::std::vec::IntoIter<MediaItem>,
|
||||||
) -> Result<(), Box<dyn Error>> {
|
finished: bool,
|
||||||
let mut page_token = None;
|
req: SearchMediaItemsRequest,
|
||||||
let mut total = 0;
|
}
|
||||||
|
|
||||||
|
impl<'a> SearchIter<'a> {
|
||||||
|
fn new(client: &'a photos::Client, req: SearchMediaItemsRequest) -> Self {
|
||||||
|
SearchIter {
|
||||||
|
client,
|
||||||
|
items: Vec::new().into_iter(),
|
||||||
|
finished: false,
|
||||||
|
req,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for SearchIter<'a> {
|
||||||
|
type Item = Result<MediaItem, photos::Error>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Result<MediaItem, photos::Error>> {
|
||||||
loop {
|
loop {
|
||||||
let resp = client
|
if let Some(v) = self.items.next() {
|
||||||
|
return Some(Ok(v));
|
||||||
|
}
|
||||||
|
if self.finished {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let resp = match self
|
||||||
|
.client
|
||||||
.media_items()
|
.media_items()
|
||||||
.search(SearchMediaItemsRequest {
|
.search(self.req.clone())
|
||||||
|
.execute_with_default_fields()
|
||||||
|
{
|
||||||
|
Ok(resp) => resp,
|
||||||
|
Err(err) => return Some(Err(err)),
|
||||||
|
};
|
||||||
|
if resp.next_page_token.is_none() {
|
||||||
|
self.finished = true;
|
||||||
|
}
|
||||||
|
self.req.page_token = resp.next_page_token;
|
||||||
|
if let Some(items) = resp.media_items {
|
||||||
|
self.items = items.into_iter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search_media_items(client: photos::Client, album_id: String) -> Result<(), Box<dyn Error>> {
|
||||||
|
let mut total = 0;
|
||||||
|
let media_items = SearchIter::new(
|
||||||
|
&client,
|
||||||
|
SearchMediaItemsRequest {
|
||||||
album_id: Some(album_id.clone()),
|
album_id: Some(album_id.clone()),
|
||||||
// 100 is the documented max.
|
// 100 is the documented max.
|
||||||
page_size: Some(100),
|
page_size: Some(100),
|
||||||
page_token,
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
},
|
||||||
.execute_with_all_fields()?;
|
);
|
||||||
|
|
||||||
let media_items = resp.media_items.ok_or("no results")?;
|
|
||||||
println!("got ({}) items", media_items.len());
|
|
||||||
total += media_items.len();
|
|
||||||
for mi in media_items {
|
for mi in media_items {
|
||||||
|
let mi = mi?;
|
||||||
|
total += 1;
|
||||||
println!(
|
println!(
|
||||||
"{} {}",
|
"{} {}",
|
||||||
mi.id.unwrap_or("NO ID".to_string()),
|
mi.id.unwrap_or("NO ID".to_string()),
|
||||||
mi.filename.unwrap_or("NO FILENAME".to_string())
|
mi.filename.unwrap_or("NO FILENAME".to_string())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
page_token = resp.next_page_token;
|
|
||||||
if page_token.is_none() {
|
|
||||||
println!("({}) items total", total);
|
println!("({}) items total", total);
|
||||||
return Ok(());
|
Ok(())
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_albums(
|
fn list_albums(client: photos::Client, title_filter: Option<Regex>) -> Result<(), Box<dyn Error>> {
|
||||||
client: google_photoslibrary1::Client,
|
|
||||||
title_filter: Option<Regex>,
|
|
||||||
) -> Result<(), Box<dyn Error>> {
|
|
||||||
for album in client
|
for album in client
|
||||||
.shared_albums()
|
.shared_albums()
|
||||||
.list()
|
.list()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user