2023-04-10 00:13:18 +02:00
|
|
|
use std::path::PathBuf;
|
2023-04-14 16:21:25 +02:00
|
|
|
use std::{ffi::OsString, io};
|
2023-04-10 00:13:18 +02:00
|
|
|
|
2023-04-14 16:21:25 +02:00
|
|
|
use ratatui::{backend::CrosstermBackend, Terminal};
|
2023-04-10 00:13:18 +02:00
|
|
|
use structopt::StructOpt;
|
|
|
|
|
|
|
|
use musichoard::{
|
2023-04-13 14:09:59 +02:00
|
|
|
collection::MhCollectionManager,
|
2023-04-14 16:21:25 +02:00
|
|
|
database::{
|
|
|
|
json::{backend::JsonDatabaseFileBackend, JsonDatabase},
|
|
|
|
Database,
|
|
|
|
},
|
|
|
|
library::{
|
|
|
|
beets::{
|
2023-04-27 20:09:45 +02:00
|
|
|
executor::{ssh::BeetsLibrarySshExecutor, BeetsLibraryProcessExecutor},
|
2023-04-14 16:21:25 +02:00
|
|
|
BeetsLibrary,
|
|
|
|
},
|
|
|
|
Library,
|
|
|
|
},
|
2023-04-13 14:09:59 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
mod tui;
|
2023-04-27 19:05:37 +02:00
|
|
|
use tui::ui::MhUi;
|
|
|
|
use tui::{event::EventChannel, handler::TuiEventHandler, listener::TuiEventListener, Tui};
|
2023-04-10 00:13:18 +02:00
|
|
|
|
|
|
|
#[derive(StructOpt)]
|
|
|
|
struct Opt {
|
2023-04-14 16:21:25 +02:00
|
|
|
#[structopt(long = "ssh", name = "beets SSH URI")]
|
|
|
|
beets_ssh_uri: Option<OsString>,
|
|
|
|
|
|
|
|
#[structopt(long = "beets", name = "beets config file path")]
|
|
|
|
beets_config_file_path: Option<OsString>,
|
2023-04-10 00:13:18 +02:00
|
|
|
|
|
|
|
#[structopt(
|
|
|
|
long = "database",
|
|
|
|
name = "database file path",
|
2023-04-14 16:21:25 +02:00
|
|
|
default_value = "database.json"
|
2023-04-10 00:13:18 +02:00
|
|
|
)]
|
|
|
|
database_file_path: PathBuf,
|
|
|
|
}
|
|
|
|
|
2023-04-14 16:21:25 +02:00
|
|
|
fn with<LIB: Library, DB: Database>(lib: LIB, db: DB) {
|
|
|
|
let collection_manager = MhCollectionManager::new(lib, db);
|
2023-04-13 14:09:59 +02:00
|
|
|
|
|
|
|
// Initialize the terminal user interface.
|
|
|
|
let backend = CrosstermBackend::new(io::stdout());
|
|
|
|
let terminal = Terminal::new(backend).expect("failed to initialise terminal");
|
|
|
|
|
|
|
|
let channel = EventChannel::new();
|
|
|
|
let listener = TuiEventListener::new(channel.sender());
|
|
|
|
let handler = TuiEventHandler::new(channel.receiver());
|
|
|
|
|
2023-04-27 19:05:37 +02:00
|
|
|
let ui = MhUi::new(collection_manager).expect("failed to initialise ui");
|
2023-04-13 14:09:59 +02:00
|
|
|
|
|
|
|
// Run the TUI application.
|
2023-04-27 19:05:37 +02:00
|
|
|
Tui::run(terminal, ui, handler, listener).expect("failed to run tui");
|
2023-04-13 14:09:59 +02:00
|
|
|
}
|
|
|
|
|
2023-04-14 16:21:25 +02:00
|
|
|
fn main() {
|
|
|
|
// Create the application.
|
|
|
|
let opt = Opt::from_args();
|
|
|
|
|
|
|
|
if let Some(uri) = opt.beets_ssh_uri {
|
|
|
|
let uri = uri.into_string().expect("invalid SSH URI");
|
2023-04-27 19:34:07 +02:00
|
|
|
let beets_config_file_path = opt
|
|
|
|
.beets_config_file_path
|
|
|
|
.map(|s| s.into_string())
|
|
|
|
.transpose()
|
|
|
|
.expect("failed to extract beets config file path");
|
|
|
|
let lib_exec = BeetsLibrarySshExecutor::new(uri)
|
|
|
|
.expect("failed to initialise beets")
|
|
|
|
.config(beets_config_file_path);
|
2023-04-14 16:21:25 +02:00
|
|
|
let db_exec = JsonDatabaseFileBackend::new(&opt.database_file_path);
|
|
|
|
with(BeetsLibrary::new(lib_exec), JsonDatabase::new(db_exec));
|
|
|
|
} else {
|
|
|
|
let lib_exec = BeetsLibraryProcessExecutor::default().config(opt.beets_config_file_path);
|
|
|
|
let db_exec = JsonDatabaseFileBackend::new(&opt.database_file_path);
|
|
|
|
with(BeetsLibrary::new(lib_exec), JsonDatabase::new(db_exec));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-13 14:09:59 +02:00
|
|
|
#[cfg(test)]
|
|
|
|
#[macro_use]
|
|
|
|
mod testlib;
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use mockall::mock;
|
|
|
|
use once_cell::sync::Lazy;
|
|
|
|
|
|
|
|
use musichoard::collection::{self, Collection, CollectionManager};
|
|
|
|
use musichoard::*;
|
|
|
|
|
|
|
|
pub static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| collection!());
|
|
|
|
|
|
|
|
mock! {
|
|
|
|
pub CollectionManager {}
|
|
|
|
|
|
|
|
impl CollectionManager for CollectionManager {
|
|
|
|
fn rescan_library(&mut self) -> Result<(), collection::Error>;
|
|
|
|
fn save_to_database(&mut self) -> Result<(), collection::Error>;
|
|
|
|
fn get_collection(&self) -> &Collection;
|
|
|
|
}
|
|
|
|
}
|
2023-04-10 00:13:18 +02:00
|
|
|
}
|