Skip to content

Commit bb0fd95

Browse files
committed
refactor: setup monorepo structure
1 parent 3e9cdae commit bb0fd95

File tree

14 files changed

+462
-327
lines changed

14 files changed

+462
-327
lines changed

.github/workflows/build-binaries-and-update-release.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ jobs:
4343
target: ${{ matrix.target }}
4444

4545
- name: Build project
46-
run: cargo build --release --target ${{ matrix.target }}
46+
run: cargo build --bin ffzap --release --target ${{ matrix.target }}
4747

4848
- name: Prepare archive
4949
run: |

Cargo.lock

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
1-
[package]
2-
name = "ffzap"
1+
[workspace]
2+
members = [
3+
"cli",
4+
"shared",
5+
"ui"
6+
]
7+
resolver = "2"
8+
9+
[workspace.package]
310
version = "1.1.2"
411
edition = "2021"
512
description = "⚡ A multithreaded CLI for digital media processing using ffmpeg. If ffmpeg can do it, ffzap can do it - as many files in parallel as your system can handle."
@@ -9,7 +16,7 @@ repository = "https://github.com/CodeF0x/ffzap"
916

1017
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
1118

12-
[dependencies]
19+
[workspace.dependencies]
1320
chrono = "0.4.39"
1421
clap = { version = "4.5.20", features = ["derive"] }
1522
dirs = "6.0.0"

cli/Cargo.toml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[package]
2+
name = "ffzap"
3+
version.workspace = true
4+
edition.workspace = true
5+
description.workspace = true
6+
license-file.workspace = true
7+
keywords.workspace = true
8+
repository.workspace = true
9+
10+
[dependencies]
11+
ffzap-shared = { path = "../shared" }
12+
clap.workspace = true

cli/src/main.rs

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
use clap::Parser;
2+
use ffzap_shared::{CmdArgs, Logger, Processor, Progress};
3+
use std::fs;
4+
use std::io::ErrorKind;
5+
use std::process::exit;
6+
use std::sync::Arc;
7+
8+
fn main() {
9+
let cmd_args = CmdArgs::parse();
10+
11+
if cmd_args.eta {
12+
println!("Warning: ETA is a highly experimental feature and prone to absurd estimations. If your encoding process has long pauses in-between each processed file, you WILL experience incredibly inaccurate estimations!");
13+
println!("This is due to unwanted behaviour in one of ffzap's dependencies and cannot be fixed by ffzap.");
14+
}
15+
16+
let paths = load_paths(&cmd_args);
17+
let progress = Arc::new(Progress::new(paths.len(), cmd_args.eta));
18+
let logger = Arc::new(Logger::new(Arc::clone(&progress)));
19+
let processor = Processor::new(Arc::clone(&logger), Arc::clone(&progress));
20+
21+
processor.process_files(
22+
paths,
23+
cmd_args.thread_count,
24+
cmd_args.ffmpeg_options,
25+
cmd_args.output,
26+
cmd_args.overwrite,
27+
cmd_args.verbose,
28+
cmd_args.delete,
29+
);
30+
31+
let final_output = format!(
32+
"{} out of {} files have been successful. A detailed log has been written to {}",
33+
progress.value(),
34+
progress.len(),
35+
logger.get_log_path()
36+
);
37+
println!("{final_output}");
38+
39+
let failed_paths = processor.get_failed_paths();
40+
logger.append_failed_paths_to_log(&std::sync::Mutex::new(failed_paths.clone()).lock().unwrap());
41+
42+
if cmd_args.verbose && !failed_paths.is_empty() {
43+
println!("\nThe following files were not processed due to the errors above:");
44+
for path in failed_paths.iter() {
45+
println!("{path}");
46+
}
47+
}
48+
}
49+
50+
fn load_paths(cmd_args: &CmdArgs) -> Vec<String> {
51+
if let Some(input_file_path) = &cmd_args.file_list {
52+
match fs::read_to_string(input_file_path) {
53+
Ok(contents) => contents
54+
.trim()
55+
.split('\n')
56+
.map(|s| s.trim().to_string())
57+
.collect(),
58+
Err(err) => {
59+
match err.kind() {
60+
ErrorKind::NotFound => {
61+
eprintln!("No file found at {input_file_path}.");
62+
exit(1);
63+
}
64+
ErrorKind::PermissionDenied => {
65+
eprintln!("Permission denied when reading file {input_file_path}.");
66+
exit(1);
67+
}
68+
ErrorKind::InvalidData => {
69+
eprintln!("The contents of {input_file_path} contain invalid data. Please make sure it is encoded as UTF-8.");
70+
exit(1);
71+
}
72+
ErrorKind::IsADirectory => {
73+
eprintln!("The path {input_file_path} is a directory.");
74+
exit(1);
75+
}
76+
_ => {
77+
eprintln!("An error has occurred reading the file at path {input_file_path}: {:?}.", err);
78+
exit(1);
79+
}
80+
}
81+
}
82+
}
83+
} else {
84+
cmd_args.input.clone().unwrap()
85+
}
86+
}

shared/Cargo.toml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[package]
2+
name = "ffzap-shared"
3+
version.workspace = true
4+
edition.workspace = true
5+
description.workspace = true
6+
license-file.workspace = true
7+
keywords.workspace = true
8+
repository.workspace = true
9+
10+
[dependencies]
11+
chrono.workspace = true
12+
dirs.workspace = true
13+
indicatif.workspace = true
14+
clap.workspace = true

shared/src/args.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
use clap::Parser;
2+
3+
#[derive(Parser, Debug, Clone)]
4+
#[command(version, about)]
5+
pub struct CmdArgs {
6+
/// The amount of threads you want to utilize. most systems can handle 2. Go higher if you have a powerful computer. Default is 2. Can't be lower than 1
7+
#[arg(short, long, default_value_t = 2, value_parser = clap::value_parser!(u16).range(1..))]
8+
pub thread_count: u16,
9+
10+
/// Options you want to pass to ffmpeg. For the output file name, use --output
11+
#[arg(short, long, allow_hyphen_values = true)]
12+
pub ffmpeg_options: Option<String>,
13+
14+
/// The files you want to process.
15+
#[arg(short, long, num_args = 1.., required_unless_present = "file_list", conflicts_with = "file_list")]
16+
pub input: Option<Vec<String>>,
17+
18+
/// Path to a file containing paths to process. One path per line
19+
#[arg(long, required_unless_present = "input", conflicts_with = "input")]
20+
pub file_list: Option<String>,
21+
22+
/// If ffmpeg should overwrite files if they already exist. Default is false
23+
#[arg(long, default_value_t = false)]
24+
pub overwrite: bool,
25+
26+
/// If verbose logs should be shown while ffzap is running
27+
#[arg(long, default_value_t = false)]
28+
pub verbose: bool,
29+
30+
/// Delete the source file after it was successfully processed. If the process fails, the file is kept.
31+
#[arg(long, default_value_t = false)]
32+
pub delete: bool,
33+
34+
/// Displays the current eta in the progressbar
35+
#[arg(long, default_value_t = false)]
36+
pub eta: bool,
37+
38+
/// Specify the output file pattern. Use placeholders to customize file paths:
39+
///
40+
/// {{dir}} - Entire specified file path, e.g. ./path/to/file.txt -> ?./path/to/
41+
///
42+
/// {{name}} - Original file's name (without extension)
43+
///
44+
/// {{ext}} - Original file's extension
45+
///
46+
/// Example: /destination/{{dir}}/{{name}}_transcoded.{{ext}}
47+
///
48+
/// Outputs the file in /destination, mirroring the original structure and keeping both the file extension and name, while adding _transcoded to the name.
49+
#[arg(short, long)]
50+
pub output: String,
51+
}

shared/src/lib.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
pub mod logger;
2+
pub mod progress;
3+
pub mod processor;
4+
pub mod args;
5+
6+
pub use logger::Logger;
7+
pub use progress::Progress;
8+
pub use processor::Processor;
9+
pub use args::CmdArgs;

src/logger.rs renamed to shared/src/logger.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ use std::io::Write;
55
use std::path::{Display, PathBuf};
66
use std::sync::{Arc, Mutex, MutexGuard};
77

8-
pub(crate) struct Logger {
8+
pub struct Logger {
99
progress: Arc<Progress>,
1010
log_file: Arc<Mutex<File>>,
1111
log_path: PathBuf,
1212
}
1313

1414
impl Logger {
15-
pub(crate) fn new(progress: Arc<Progress>) -> Self {
15+
pub fn new(progress: Arc<Progress>) -> Self {
1616
let path_file_tuple = Self::setup_log_dir_and_create_log_file();
1717

1818
let log_path = path_file_tuple.0;
@@ -25,7 +25,7 @@ impl Logger {
2525
}
2626
}
2727

28-
pub(crate) fn log_info(&self, line: String, thread: u16, print: bool) {
28+
pub fn log_info(&self, line: String, thread: u16, print: bool) {
2929
let line = format!("[INFO in THREAD {thread}] -- {line}\n");
3030

3131
self.write_to_log(&line);
@@ -35,7 +35,7 @@ impl Logger {
3535
}
3636
}
3737

38-
pub(crate) fn log_error(&self, line: String, thread: u16, print: bool) {
38+
pub fn log_error(&self, line: String, thread: u16, print: bool) {
3939
let line = format!("[ERROR in THREAD {thread} -- {line}\n");
4040

4141
self.write_to_log(&line);
@@ -45,7 +45,7 @@ impl Logger {
4545
}
4646
}
4747

48-
pub(crate) fn append_failed_paths_to_log(&self, paths: &MutexGuard<Vec<String>>) {
48+
pub fn append_failed_paths_to_log(&self, paths: &MutexGuard<Vec<String>>) {
4949
if paths.len() == 0 {
5050
return;
5151
}
@@ -59,7 +59,7 @@ impl Logger {
5959
self.write_to_log(&to_write);
6060
}
6161

62-
pub(crate) fn get_log_path(&self) -> Display {
62+
pub fn get_log_path(&self) -> Display {
6363
self.log_path.display()
6464
}
6565

@@ -122,4 +122,4 @@ impl Logger {
122122
fn print(&self, line: String) {
123123
self.progress.println(line);
124124
}
125-
}
125+
}

0 commit comments

Comments
 (0)