Implement ServeAndSync.
This commit is contained in:
parent
89037b6b24
commit
a96fe1da9d
121
src/main.rs
121
src/main.rs
@ -2,12 +2,14 @@ use std::collections::HashMap;
|
||||
use std::error::Error;
|
||||
use std::net::SocketAddr;
|
||||
use std::path::PathBuf;
|
||||
use std::thread;
|
||||
use std::time;
|
||||
|
||||
use google_api_auth;
|
||||
use google_photoslibrary1 as photos;
|
||||
use hexihasher;
|
||||
use lazy_static::lazy_static;
|
||||
use log::{debug, info};
|
||||
use log::{debug, error, info};
|
||||
use photos::schemas::{Album, MediaItem, SearchMediaItemsRequest};
|
||||
use regex::Regex;
|
||||
use structopt::StructOpt;
|
||||
@ -16,6 +18,31 @@ use yup_oauth2::{Authenticator, InstalledFlow};
|
||||
use photosync::library::Library;
|
||||
use photosync::web;
|
||||
|
||||
fn parse_duration(src: &str) -> Result<time::Duration, std::num::ParseIntError> {
|
||||
let secs = str::parse::<u64>(src)?;
|
||||
Ok(time::Duration::from_secs(secs))
|
||||
}
|
||||
|
||||
#[derive(Debug, StructOpt)]
|
||||
struct Sync {
|
||||
#[structopt(flatten)]
|
||||
auth: Auth,
|
||||
/// Optional album title to filter. Default will mirror all albums.
|
||||
#[structopt(short, long)]
|
||||
title_filter: Option<Regex>,
|
||||
/// Directory to store sync.
|
||||
root: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Debug, StructOpt)]
|
||||
struct Serve {
|
||||
/// Directory of data fetched by `sync`.
|
||||
root: PathBuf,
|
||||
/// HTTP address to listen for web requests.
|
||||
#[structopt(long = "addr", default_value = "0.0.0.0:0")]
|
||||
addr: SocketAddr,
|
||||
}
|
||||
|
||||
#[derive(Debug, StructOpt)]
|
||||
enum Command {
|
||||
/// List albums for the user of the given credentials. Optionally title filter.
|
||||
@ -31,16 +58,19 @@ enum Command {
|
||||
},
|
||||
Sync {
|
||||
#[structopt(flatten)]
|
||||
auth: Auth,
|
||||
/// Optional album title to filter. Default will mirror all albums.
|
||||
#[structopt(short, long)]
|
||||
title_filter: Option<Regex>,
|
||||
/// Directory to store sync.
|
||||
output: PathBuf,
|
||||
sync: Sync,
|
||||
},
|
||||
Serve {
|
||||
/// Directory of data fetched by `sync`.
|
||||
root: PathBuf,
|
||||
#[structopt(flatten)]
|
||||
serve: Serve,
|
||||
},
|
||||
ServeAndSync {
|
||||
/// Sync albums at given interval.
|
||||
#[structopt(parse(try_from_str = parse_duration))]
|
||||
interval: time::Duration,
|
||||
|
||||
#[structopt(flatten)]
|
||||
sync: Sync,
|
||||
/// HTTP address to listen for web requests.
|
||||
#[structopt(long = "addr", default_value = "0.0.0.0:0")]
|
||||
addr: SocketAddr,
|
||||
@ -192,10 +222,9 @@ lazy_static! {
|
||||
|
||||
fn sync_albums(
|
||||
client: &photos::Client,
|
||||
title_filter: Option<Regex>,
|
||||
output_dir: PathBuf,
|
||||
title_filter: &Option<Regex>,
|
||||
lib: &Library,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let lib = Library::new(output_dir)?;
|
||||
let albums = list_albums(client, title_filter)?;
|
||||
info!("albums {:?}", albums);
|
||||
lib.create_album_index(&albums)?;
|
||||
@ -236,12 +265,18 @@ fn print_albums(albums: Vec<Album>) {
|
||||
|
||||
fn list_albums(
|
||||
client: &photos::Client,
|
||||
title_filter: Option<Regex>,
|
||||
title_filter: &Option<Regex>,
|
||||
) -> Result<Vec<Album>, Box<dyn Error>> {
|
||||
Ok(client
|
||||
.shared_albums()
|
||||
.albums()
|
||||
.list()
|
||||
.iter_shared_albums_with_all_fields()
|
||||
.iter_albums_with_all_fields()
|
||||
.chain(
|
||||
client
|
||||
.shared_albums()
|
||||
.list()
|
||||
.iter_shared_albums_with_all_fields(),
|
||||
)
|
||||
.filter_map(|a| a.ok())
|
||||
.filter(|a| {
|
||||
match (&title_filter, &a.title) {
|
||||
@ -258,8 +293,23 @@ fn list_albums(
|
||||
.collect())
|
||||
}
|
||||
|
||||
pub fn serve(addr: SocketAddr, root: PathBuf) -> Result<(), Box<dyn Error>> {
|
||||
web::run(addr, root)
|
||||
fn background_sync(
|
||||
client: photos::Client,
|
||||
interval: time::Duration,
|
||||
title_filter: Option<Regex>,
|
||||
lib: Library,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
thread::spawn(move || loop {
|
||||
if let Err(err) = sync_albums(&client, &title_filter, &lib) {
|
||||
error!("Error syncing: {}", err);
|
||||
}
|
||||
thread::sleep(interval);
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn serve(addr: SocketAddr, lib: Library) -> Result<(), Box<dyn Error>> {
|
||||
web::run(addr, lib)
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
@ -273,7 +323,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
match opt.cmd {
|
||||
Command::ListAlbums { auth, title_filter } => {
|
||||
let client = new_client(&auth.credentials, &auth.token_cache)?;
|
||||
print_albums(list_albums(&client, title_filter)?);
|
||||
print_albums(list_albums(&client, &title_filter)?);
|
||||
Ok(())
|
||||
}
|
||||
Command::SearchMediaItems { auth, album_id } => {
|
||||
@ -282,14 +332,39 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
Ok(())
|
||||
}
|
||||
Command::Sync {
|
||||
auth,
|
||||
title_filter,
|
||||
output,
|
||||
sync:
|
||||
Sync {
|
||||
auth,
|
||||
title_filter,
|
||||
root,
|
||||
},
|
||||
} => {
|
||||
let client = new_client(&auth.credentials, &auth.token_cache)?;
|
||||
sync_albums(&client, title_filter, output)?;
|
||||
let lib = Library::new(root)?;
|
||||
sync_albums(&client, &title_filter, &lib)?;
|
||||
Ok(())
|
||||
}
|
||||
Command::Serve {
|
||||
serve: Serve { addr, root },
|
||||
} => {
|
||||
let lib = Library::new(root)?;
|
||||
serve(addr, lib)
|
||||
}
|
||||
Command::ServeAndSync {
|
||||
interval,
|
||||
sync:
|
||||
Sync {
|
||||
auth,
|
||||
title_filter,
|
||||
root,
|
||||
},
|
||||
addr,
|
||||
} => {
|
||||
let client = new_client(&auth.credentials, &auth.token_cache)?;
|
||||
let lib = Library::new(root)?;
|
||||
background_sync(client, interval, title_filter, lib.clone())?;
|
||||
serve(addr, lib)?;
|
||||
Ok(())
|
||||
}
|
||||
Command::Serve { addr, root } => serve(addr, root),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
use std::error::Error;
|
||||
use std::net::SocketAddr;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use log::warn;
|
||||
use prometheus::Encoder;
|
||||
@ -98,11 +97,10 @@ fn image(
|
||||
}
|
||||
|
||||
#[derive(RustEmbed)]
|
||||
#[folder = "react-debug/build/"]
|
||||
#[folder = "react-slideshow/build/"]
|
||||
struct Asset;
|
||||
|
||||
pub fn run(addr: SocketAddr, root: PathBuf) -> Result<(), Box<dyn Error>> {
|
||||
let lib = Library::new(root)?;
|
||||
pub fn run(addr: SocketAddr, lib: Library) -> Result<(), Box<dyn Error>> {
|
||||
let lib = warp::any().map(move || lib.clone());
|
||||
|
||||
let index = warp::get2().and(warp::path::full()).and_then(index);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user