165 lines
5.3 KiB
Rust
165 lines
5.3 KiB
Rust
use clap::{App, Arg};
|
|
use cursive::traits::*;
|
|
use cursive::views::{Checkbox, Dialog, ListView, ProgressBar, TextView};
|
|
use cursive::Cursive;
|
|
use failure::Error;
|
|
use lazy_static::lazy_static;
|
|
use std::ffi::OsStr;
|
|
use std::os::unix::process::CommandExt;
|
|
use std::path::PathBuf;
|
|
use std::process::Command;
|
|
use std::sync::{Arc, Mutex};
|
|
|
|
use crate::registry::Registry;
|
|
|
|
mod registry;
|
|
|
|
lazy_static! {
|
|
static ref REGISTRY: Arc<Mutex<Registry>> = Arc::new(Mutex::new(Registry::default()));
|
|
}
|
|
|
|
fn main() -> Result<(), Error> {
|
|
let matches = App::new("Music Sync")
|
|
.version("0.1.0")
|
|
.author("Paul van Tilburg <paul@luon.net>")
|
|
.about("Syncs selected music (albums) to a remote location using rsync")
|
|
.arg(Arg::with_name("device").index(1).required(true))
|
|
.arg(Arg::with_name("directory").index(2).required(true))
|
|
.get_matches();
|
|
let device = matches.value_of("device").unwrap();
|
|
let base_path = matches.value_of("directory").unwrap();
|
|
{
|
|
let mut registry = REGISTRY.lock().unwrap();
|
|
registry.device = String::from(device);
|
|
registry.base_path = PathBuf::from(base_path);
|
|
}
|
|
|
|
let mut ui = Cursive::default();
|
|
load_albums(&mut ui);
|
|
|
|
ui.set_fps(10);
|
|
ui.run();
|
|
Ok(())
|
|
}
|
|
|
|
fn load_albums(ui: &mut Cursive) {
|
|
let mut registry = REGISTRY.lock().unwrap();
|
|
if let Err(error) = registry.load_albums_file() {
|
|
eprintln!("Something went wrong: {}", error);
|
|
quit(ui);
|
|
}
|
|
|
|
let cb = ui.cb_sink().clone();
|
|
ui.add_layer(
|
|
Dialog::around(
|
|
ProgressBar::new()
|
|
.range(0, registry.albums_list.len())
|
|
.with_task(move |counter| {
|
|
let mut registry = REGISTRY.lock().unwrap();
|
|
if let Err(error) = registry.load_albums_fs(&counter) {
|
|
eprintln!("Something went wrong: {}", error);
|
|
cb.send(Box::new(quit));
|
|
} else {
|
|
cb.send(Box::new(select_albums));
|
|
}
|
|
}),
|
|
).title("Loading list of albums…"),
|
|
);
|
|
}
|
|
|
|
fn album_name(album_path: &PathBuf) -> &str {
|
|
album_path
|
|
.file_name()
|
|
.unwrap_or_else(|| OsStr::new("<Couldn't determine filename>"))
|
|
.to_str()
|
|
.unwrap_or("<Non-UTF-8 characters found>")
|
|
}
|
|
|
|
fn select_albums(ui: &mut Cursive) {
|
|
let registry = REGISTRY.lock().unwrap();
|
|
let added_albums = registry.added_albums();
|
|
let existing_albums = registry.existing_albums();
|
|
let removed_albums = registry.removed_albums();
|
|
// FIXME: Use a custom view for this.
|
|
let list_view = ListView::new()
|
|
.with(|list_view| {
|
|
list_view.add_child("--- New", Checkbox::new().disabled());
|
|
for album_path in added_albums {
|
|
let album_name = album_name(&album_path);
|
|
let album_path = album_path.clone();
|
|
|
|
let checkbox = Checkbox::new().on_change(move |_, checked| {
|
|
let mut registry = REGISTRY.lock().unwrap();
|
|
registry.select_album(&album_path, checked);
|
|
});
|
|
list_view.add_child(album_name, checkbox);
|
|
}
|
|
list_view.add_child("--- Existing ", Checkbox::new().disabled());
|
|
for album_path in existing_albums {
|
|
let album_name = album_name(&album_path);
|
|
let album_path = album_path.clone();
|
|
let selected = registry.selected_albums.contains(&album_path);
|
|
|
|
let mut checkbox = Checkbox::new().on_change(move |_, checked| {
|
|
let mut registry = REGISTRY.lock().unwrap();
|
|
registry.select_album(&album_path, checked);
|
|
});
|
|
if selected {
|
|
checkbox.check();
|
|
}
|
|
list_view.add_child(album_name, checkbox)
|
|
}
|
|
list_view.add_child("--- Gone ", Checkbox::new().disabled());
|
|
for album_path in removed_albums {
|
|
let mut checkbox = Checkbox::new().disabled();
|
|
if registry.selected_albums.contains(album_path) {
|
|
checkbox.check();
|
|
}
|
|
list_view.add_child(album_name(album_path), checkbox);
|
|
}
|
|
}).scrollable();
|
|
|
|
ui.pop_layer();
|
|
ui.add_layer(
|
|
Dialog::new()
|
|
.title("Select or unselect albums")
|
|
.button("Quit", |ui| quit(ui))
|
|
.button("Apply", |ui| save_albums(ui))
|
|
.content(list_view),
|
|
);
|
|
}
|
|
|
|
fn save_albums(ui: &mut Cursive) {
|
|
let registry = REGISTRY.lock().unwrap();
|
|
if let Err(error) = registry.save_albums_file() {
|
|
eprintln!("Something went wrong: {}", error);
|
|
quit(ui);
|
|
}
|
|
|
|
ui.pop_layer();
|
|
ui.add_layer(
|
|
Dialog::around(TextView::new("All albums have been saved!\nSynchronise?"))
|
|
.button("Yes", |ui| sync_albums(ui))
|
|
.button("No", |ui| ui.quit()),
|
|
);
|
|
}
|
|
|
|
fn sync_albums(ui: &mut Cursive) {
|
|
let registry = REGISTRY.lock().unwrap();
|
|
ui.quit();
|
|
|
|
Command::new("echo")
|
|
.arg("rsync")
|
|
.arg("-vaP")
|
|
.arg(&format!("--include-from={}.list.new", registry.device))
|
|
.arg("--exclude=\"*\"")
|
|
.arg("--delete")
|
|
.arg(®istry.base_path)
|
|
.arg("target_path")
|
|
.exec();
|
|
}
|
|
|
|
fn quit(ui: &mut Cursive) {
|
|
ui.quit();
|
|
}
|