2021-04-29 17:58:37 +01:00
use std ::{ fs ::File , io ::Read , path ::Path } ;
2021-02-06 09:59:03 +00:00
2021-04-29 17:58:37 +01:00
use chrono ::{ DateTime , Local } ;
2020-11-24 06:58:50 +00:00
use clap ::{ App , AppSettings , Arg } ;
2021-04-29 17:58:37 +01:00
use flexi_logger ::LevelFilter as LogLevel ;
use crate ::logs ::init_logger ;
2020-05-16 08:09:44 +01:00
2021-02-06 09:59:03 +00:00
pub fn cli_init ( ) -> AppConfig {
let app = App ::new ( " paperoni " )
2020-11-24 06:58:50 +00:00
. settings ( & [
AppSettings ::ArgRequiredElseHelp ,
AppSettings ::UnifiedHelpMessage ,
] )
2021-04-17 10:08:24 +01:00
. version ( clap ::crate_version! ( ) )
2020-11-24 06:58:50 +00:00
. about (
2021-04-30 04:55:02 +01:00
" Paperoni is a CLI tool made in Rust for downloading web articles as EPUBs " ,
2020-11-24 06:58:50 +00:00
)
. arg (
Arg ::with_name ( " urls " )
. help ( " Urls of web articles " )
. multiple ( true ) ,
)
2021-02-01 08:28:07 +00:00
. arg (
Arg ::with_name ( " file " )
. short ( " f " )
. long ( " file " )
. help ( " Input file containing links " )
. takes_value ( true ) ,
2021-02-11 10:51:21 +00:00
)
. arg (
Arg ::with_name ( " output_name " )
. long ( " merge " )
. help ( " Merge multiple articles into a single epub " )
. long_help ( " Merge multiple articles into a single epub that will be given the name provided " )
. takes_value ( true ) ,
2021-02-21 09:40:17 +00:00
) . arg (
Arg ::with_name ( " max_conn " )
. long ( " max_conn " )
. help ( " The maximum number of concurrent HTTP connections when downloading articles. Default is 8 " )
. long_help ( " The maximum number of concurrent HTTP connections when downloading articles. Default is 8. \n NOTE: It is advised to use as few connections as needed i.e between 1 and 50. Using more connections can end up overloading your network card with too many concurrent requests. " )
2021-04-24 13:50:43 +01:00
. takes_value ( true ) )
. arg (
2021-04-29 17:58:37 +01:00
Arg ::with_name ( " verbosity " )
. short ( " v " )
. multiple ( true )
2021-04-30 04:55:02 +01:00
. help ( " Enables logging of events and set the verbosity level. Use --help to read on its usage " )
2021-04-29 17:58:37 +01:00
. long_help (
" This takes upto 4 levels of verbosity in the following order.
- Error ( - v )
- Warn ( - vv )
- Info ( - vvv )
- Debug ( - vvvv )
When this flag is passed , it disables the progress bars and logs to stderr .
If you would like to send the logs to a file ( and enable progress bars ) , pass the log - to - file flag . "
)
. takes_value ( false ) )
. arg (
Arg ::with_name ( " log-to-file " )
. long ( " log-to-file " )
. help ( " Enables logging of events to a file located in .paperoni/logs with a default log level of debug. Use -v to specify the logging level " )
2021-04-24 13:50:43 +01:00
. takes_value ( false ) ) ;
2021-02-06 09:59:03 +00:00
let arg_matches = app . get_matches ( ) ;
2021-04-29 17:58:37 +01:00
2021-02-06 09:59:03 +00:00
let mut urls : Vec < String > = match arg_matches . value_of ( " file " ) {
Some ( file_name ) = > {
if let Ok ( mut file ) = File ::open ( file_name ) {
let mut content = String ::new ( ) ;
match file . read_to_string ( & mut content ) {
Ok ( _ ) = > content
. lines ( )
. filter ( | line | ! line . is_empty ( ) )
. map ( | line | line . to_owned ( ) )
. collect ( ) ,
Err ( _ ) = > vec! [ ] ,
}
} else {
println! ( " Unable to open file: {} " , file_name ) ;
vec! [ ]
}
}
None = > vec! [ ] ,
} ;
if let Some ( vals ) = arg_matches . values_of ( " urls " ) {
urls . extend (
vals . filter ( | val | ! val . is_empty ( ) )
. map ( | val | val . to_string ( ) ) ,
) ;
}
2021-02-21 09:40:17 +00:00
let max_conn = arg_matches
. value_of ( " max_conn " )
. map ( | conn_str | conn_str . parse ::< usize > ( ) . ok ( ) )
. flatten ( )
. map ( | max | if max > 0 { max } else { 1 } )
. unwrap_or ( 8 ) ;
let mut app_config = AppConfig ::new ( max_conn ) ;
2021-02-06 09:59:03 +00:00
app_config . set_urls ( urls ) ;
2021-04-29 17:58:37 +01:00
2021-02-11 10:51:21 +00:00
if let Some ( name ) = arg_matches . value_of ( " output_name " ) {
2021-04-29 17:58:37 +01:00
let file_path = Path ::new ( name ) ;
2021-04-30 05:47:25 +01:00
if file_path . is_dir ( ) {
eprintln! ( " {:?} is a directory " , name ) ;
2021-04-29 17:58:37 +01:00
std ::process ::exit ( 1 ) ;
}
2021-04-30 05:47:25 +01:00
let file_name = if file_path . extension ( ) . is_some ( ) {
2021-02-11 10:51:21 +00:00
name . to_owned ( )
} else {
name . to_owned ( ) + " .epub "
} ;
2021-04-30 05:47:25 +01:00
match std ::fs ::File ::create ( & file_name ) {
Ok ( _ ) = > ( ) ,
Err ( e ) = > {
eprintln! ( " Unable to create file {:?} \n {} " , file_path , e ) ;
std ::process ::exit ( 1 )
}
}
2021-04-29 17:58:37 +01:00
app_config . merged = Some ( file_name ) ;
2021-02-11 10:51:21 +00:00
}
2021-04-29 17:58:37 +01:00
if arg_matches . is_present ( " verbosity " ) {
if ! arg_matches . is_present ( " log-to-file " ) {
app_config . can_disable_progress_bar = true ;
}
let log_levels : [ LogLevel ; 5 ] = [
LogLevel ::Off ,
LogLevel ::Error ,
2021-04-30 04:42:08 +01:00
LogLevel ::Warn ,
LogLevel ::Info ,
LogLevel ::Debug ,
2021-04-29 17:58:37 +01:00
] ;
let level = arg_matches . occurrences_of ( " verbosity " ) . clamp ( 0 , 4 ) as usize ;
app_config . log_level = log_levels [ level ] ;
}
if arg_matches . is_present ( " log-to-file " ) {
app_config . log_level = LogLevel ::Debug ;
app_config . is_logging_to_file = true ;
2021-04-24 13:50:43 +01:00
}
2021-04-29 17:58:37 +01:00
init_logger ( & app_config ) ;
2021-02-06 09:59:03 +00:00
app_config
}
pub struct AppConfig {
urls : Vec < String > ,
2021-02-06 14:03:02 +00:00
max_conn : usize ,
2021-02-11 10:51:21 +00:00
merged : Option < String > ,
2021-04-29 17:58:37 +01:00
log_level : LogLevel ,
can_disable_progress_bar : bool ,
start_time : DateTime < Local > ,
is_logging_to_file : bool ,
2021-02-06 09:59:03 +00:00
}
impl AppConfig {
2021-02-21 09:40:17 +00:00
fn new ( max_conn : usize ) -> Self {
2021-02-06 14:03:02 +00:00
Self {
urls : vec ! [ ] ,
2021-02-21 09:40:17 +00:00
max_conn ,
2021-02-11 10:51:21 +00:00
merged : None ,
2021-04-29 17:58:37 +01:00
log_level : LogLevel ::Off ,
can_disable_progress_bar : false ,
start_time : Local ::now ( ) ,
is_logging_to_file : false ,
2021-02-06 14:03:02 +00:00
}
2021-02-06 09:59:03 +00:00
}
fn set_urls ( & mut self , urls : Vec < String > ) {
self . urls . extend ( urls ) ;
}
pub fn urls ( & self ) -> & Vec < String > {
& self . urls
}
2021-02-06 14:03:02 +00:00
pub fn max_conn ( & self ) -> usize {
self . max_conn
}
2021-02-11 10:51:21 +00:00
pub fn merged ( & self ) -> Option < & String > {
self . merged . as_ref ( )
}
2021-04-24 13:50:43 +01:00
2021-04-29 17:58:37 +01:00
pub fn log_level ( & self ) -> LogLevel {
self . log_level
}
pub fn can_disable_progress_bar ( & self ) -> bool {
self . can_disable_progress_bar
}
pub fn start_time ( & self ) -> & DateTime < Local > {
& self . start_time
}
pub fn is_logging_to_file ( & self ) -> bool {
self . is_logging_to_file
2021-04-24 13:50:43 +01:00
}
2020-05-16 08:09:44 +01:00
}