Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
tgotwig committed Jun 7, 2020
0 parents commit 1951d9d
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 0 deletions.
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/target/
Cargo.lock
**/*.rs.bk
.DS_Store
data
input.txt

*.mp4
11 changes: 11 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "vid_merger"
version = "0.1.0"
authors = ["tgotwig <[email protected]>"]
edition = "2018"

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

[dependencies]
regex = "1"
clap = { version = "3.0.0-beta.1", features = ["yaml"] }
12 changes: 12 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
run:
cargo run

build:
cargo build --release

dl-mp4:
youtube-dl -o data/1.mp4 -f 22 'https://www.youtube.com/watch?v=zGDzdps75ns'
youtube-dl -o data/2.mp4 -f 22 'https://www.youtube.com/watch?v=zGDzdps75ns'

test:
cargo run -- data/ -f mp4
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
vidmerger
15 changes: 15 additions & 0 deletions src/cli.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name: vidmerger
version: "0.1"
author: Thomas Gotwig <[email protected]>
about: A wrapper around ffmpeg which simlifies merging multiple videos 🎞
args:
- format:
short: f
long: format
about: Sets a format
required: true
takes_value: true
- DIR:
about: Sets the input file to use
required: true
index: 1
98 changes: 98 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
use std::env;
use std::process::Command;
use std::process::exit;
use std::path::PathBuf;
use std::path::Path;
use std::fs::{self, File};
use std::io::prelude::*;

use regex::Regex;
use clap::{App, load_yaml};

fn main() -> std::io::Result<()> {
if find_it("ffmpeg").is_some() || find_it("ffmpeg.exe").is_some() {
()
} else {
eprintln!("ffmpeg not found 😬");
exit(1);
}

let matches = App::from(load_yaml!("cli.yaml")).get_matches();
let file_format = matches.value_of("format").unwrap();

let dir = if matches.value_of("DIR").unwrap() == "." {
"./"
} else {
matches.value_of("DIR").unwrap()
};

if Path::new(&format!("output.{}", file_format)).exists() {
fs::remove_file(format!("output.{}", file_format))?;
}

// get sorted paths
let mut paths: Vec<_> = fs::read_dir(dir).unwrap()
.map(|r| r.unwrap())
.collect();
paths.sort_by_key(|dir| dir.path());

// Generate content for input.txt
let mut input_txt = String::new();
let re = Regex::new(
format!(r"\.{}$", regex::escape(file_format)).as_str()).unwrap();
for path in paths {
let my_path = path.path();
if re.is_match(&format!("{}", my_path.display())) {
if input_txt.chars().count() == 0 {
input_txt = format!("file '{}'", my_path.display().to_string().replace(dir, ""));
} else {
input_txt = format!("{}\nfile '{}'", input_txt, my_path.display().to_string().replace(dir, ""));
}
}
}

// write input.txt
let mut file = File::create(&format!("{}input.txt", dir))?;
file.write_all(input_txt.as_bytes())?;

// generate and write the merged video by ffmpeg
let output = if cfg!(target_os = "windows") {
Command::new("cmd")
.arg("/C")
.arg(format!(
"ffmpeg.exe -y -f concat -i {dir}input.txt -c copy {dir}output.{file_format}", file_format=file_format, dir=dir))
.output()
.expect("failed to execute process")
} else {
Command::new("sh")
.arg("-c")
.arg(format!(
"ffmpeg -y -f concat -i {dir}input.txt -c copy {dir}output.{file_format}", file_format=file_format, dir=dir))
.output()
.expect("failed to execute process")
};

if output.status.success() {
println!("Successfully generated 'output.{}'! 😆🎞", file_format);
} else {
println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
println!("Something went wrong 😖");
}

Ok(())
}

fn find_it<P>(exe_name: P) -> Option<PathBuf>
where P: AsRef<Path>,
{
env::var_os("PATH").and_then(|paths| {
env::split_paths(&paths).filter_map(|dir| {
let full_path = dir.join(&exe_name);
if full_path.is_file() {
Some(full_path)
} else {
None
}
}).next()
})
}

0 comments on commit 1951d9d

Please sign in to comment.