add simple mux command
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
target/
|
||||
result
|
@@ -20,9 +20,10 @@
|
||||
devShells = with pkgs; {
|
||||
default = mkShell
|
||||
{
|
||||
buildInputs = [
|
||||
buildInputs = with gst_all_1; [
|
||||
rust-bin.nightly.latest.default
|
||||
rust-analyzer
|
||||
ffmpeg
|
||||
];
|
||||
};
|
||||
bare = mkShell
|
||||
@@ -47,6 +48,9 @@
|
||||
nativeBuildInputs = with pkgs; [
|
||||
rust-bin.nightly.latest.default
|
||||
];
|
||||
buildInputs = with pkgs; [
|
||||
ffmpeg
|
||||
];
|
||||
cargoSha256 = "sha256-DhWWUNDpDsao6lOogoM5UfUgrUfEmZvCpY0pxmr4/mI=";
|
||||
};
|
||||
}
|
||||
|
9
general.rs
Normal file
9
general.rs
Normal file
@@ -0,0 +1,9 @@
|
||||
use serenity::framework::standard::{macros::command, CommandResult};
|
||||
use serenity::model::prelude::*;
|
||||
use serenity::prelude::*;
|
||||
|
||||
#[command]
|
||||
pub async fn ping(ctx: &Context, msg: &Message) -> CommandResult {
|
||||
msg.reply(ctx, "Pong!").await?;
|
||||
Ok(())
|
||||
}
|
9
src/commands/general.rs
Normal file
9
src/commands/general.rs
Normal file
@@ -0,0 +1,9 @@
|
||||
use serenity::framework::standard::{macros::command, CommandResult};
|
||||
use serenity::model::prelude::*;
|
||||
use serenity::prelude::*;
|
||||
|
||||
#[command]
|
||||
pub async fn ping(ctx: &Context, msg: &Message) -> CommandResult {
|
||||
msg.reply(ctx, "Pong!").await?;
|
||||
Ok(())
|
||||
}
|
2
src/commands/mod.rs
Normal file
2
src/commands/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
pub mod general;
|
||||
pub mod transcode;
|
71
src/commands/transcode.rs
Normal file
71
src/commands/transcode.rs
Normal file
@@ -0,0 +1,71 @@
|
||||
use crate::lib::ffmpeg::FfmpegTranscode;
|
||||
use serenity::{
|
||||
framework::standard::{macros::command, Args, CommandResult},
|
||||
http::AttachmentType,
|
||||
model::prelude::*,
|
||||
prelude::*,
|
||||
};
|
||||
use std::{fs::remove_file, path::Path, process::ExitStatus};
|
||||
use tokio::fs::File;
|
||||
|
||||
#[command]
|
||||
#[aliases("mux")]
|
||||
pub async fn remux(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
||||
let q: Vec<&str> = args.raw().collect::<Vec<&str>>();
|
||||
if q.len() < 2 || q.len() > 4 {
|
||||
msg.reply(
|
||||
ctx,
|
||||
"Please use the proper syntax: `xxremux <audio> <video> [audio_codec] [video_codec]` or attach something",
|
||||
)
|
||||
.await?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut trans = FfmpegTranscode::default();
|
||||
|
||||
trans.add_input(q[0]).add_input(q[1]);
|
||||
|
||||
if q.len() > 2 {
|
||||
trans.set_acodec(q[2]);
|
||||
}
|
||||
|
||||
if q.len() > 3 {
|
||||
trans.set_vcodec(q[3]);
|
||||
}
|
||||
|
||||
let ext = Path::new(&q[1]).extension().unwrap().to_str().unwrap();
|
||||
let output = format!("/tmp/{}{}.{}", "singh4-", msg.id, ext);
|
||||
|
||||
trans
|
||||
.add_flag("shortest")
|
||||
.set_output(&output)
|
||||
.add_arg("map", "0:a:0")
|
||||
.add_arg("map", "1:v:0");
|
||||
|
||||
let mut m = msg.reply_ping(ctx, "Working").await?;
|
||||
let exit_code: ExitStatus = trans.run();
|
||||
let file: File = File::open(&output).await?;
|
||||
|
||||
if !exit_code.success() {
|
||||
msg.reply(ctx, "Some error occurred, please check the inputs")
|
||||
.await?;
|
||||
} else if file.metadata().await.unwrap().len() > 8 * 1024 * 1024 {
|
||||
msg.reply(ctx, "Output file larger than 8 MB").await?;
|
||||
} else {
|
||||
m.edit(ctx, |m| m.content("Uploading")).await?;
|
||||
msg.channel_id
|
||||
.send_message(ctx, |m| {
|
||||
m.add_file(AttachmentType::File {
|
||||
file: &file,
|
||||
filename: format!("{}.{}", msg.id, ext),
|
||||
})
|
||||
.content(msg.author.mention())
|
||||
})
|
||||
.await?;
|
||||
m.delete(ctx).await?;
|
||||
}
|
||||
|
||||
remove_file(output)?;
|
||||
|
||||
Ok(())
|
||||
}
|
84
src/lib/ffmpeg.rs
Normal file
84
src/lib/ffmpeg.rs
Normal file
@@ -0,0 +1,84 @@
|
||||
use std::process::{Command, ExitStatus};
|
||||
|
||||
//Helper lib for running ffmpeg using std::process::Command
|
||||
|
||||
fn sanitize_arg<V: Into<String>>(value: V) -> String {
|
||||
let v: String = value.into();
|
||||
if v.starts_with('-') {
|
||||
v
|
||||
} else {
|
||||
format!("-{}", v)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FfmpegTranscode {
|
||||
args: Vec<String>,
|
||||
out: String,
|
||||
acodec: String,
|
||||
vcodec: String,
|
||||
}
|
||||
|
||||
impl Default for FfmpegTranscode {
|
||||
fn default() -> Self {
|
||||
FfmpegTranscode {
|
||||
args: vec![],
|
||||
out: String::from("/tmp/ffmpeg"),
|
||||
acodec: String::from("copy"),
|
||||
vcodec: String::from("copy"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FfmpegTranscode {
|
||||
pub fn add_flag<V: Into<String>>(&mut self, value: V) -> &mut Self {
|
||||
self.args.push(sanitize_arg(value));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_flags<T: Into<String>, V: IntoIterator<Item = T>>(&mut self, value: V) -> &mut Self {
|
||||
for v in value {
|
||||
self.add_flag(v);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_arg<K: Into<String>, V: ToString>(&mut self, key: K, value: V) -> &mut Self {
|
||||
self.args.push(sanitize_arg(key));
|
||||
self.args.push(value.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_input<V: ToString>(&mut self, input: V) -> &mut Self {
|
||||
self.add_arg('i', input)
|
||||
}
|
||||
|
||||
pub fn set_output<V: ToString>(&mut self, output: V) -> &mut Self {
|
||||
self.out = output.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_acodec<V: ToString>(&mut self, acodec: V) -> &mut Self {
|
||||
self.acodec = acodec.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_vcodec<V: ToString>(&mut self, vcodec: V) -> &mut Self {
|
||||
self.vcodec = vcodec.to_string();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_map(&mut self, inp: i32, s: char, out: i32) -> &mut Self {
|
||||
self.add_arg("map", format!("{}:{}:{}", inp, s, out))
|
||||
}
|
||||
|
||||
pub fn run(&self) -> ExitStatus {
|
||||
Command::new("ffmpeg")
|
||||
.args(&self.args)
|
||||
.args(vec!["-c:a", &self.acodec])
|
||||
.args(vec!["-c:v", &self.vcodec])
|
||||
.arg(&self.out)
|
||||
.status()
|
||||
.expect("FFmpeg failed to run")
|
||||
}
|
||||
}
|
1
src/lib/mod.rs
Normal file
1
src/lib/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod ffmpeg;
|
20
src/main.rs
20
src/main.rs
@@ -1,11 +1,15 @@
|
||||
mod commands;
|
||||
mod handler;
|
||||
mod lib;
|
||||
use commands::general::*;
|
||||
use commands::transcode::*;
|
||||
use handler::Handler;
|
||||
use serenity::{
|
||||
client::bridge::gateway::ShardManager,
|
||||
framework::{
|
||||
standard::{
|
||||
help_commands,
|
||||
macros::help,
|
||||
macros::{group, help},
|
||||
Args, CommandGroup, CommandResult, HelpOptions,
|
||||
},
|
||||
StandardFramework,
|
||||
@@ -22,6 +26,14 @@ impl TypeMapKey for ShardManagerContainer {
|
||||
type Value = Arc<Mutex<ShardManager>>;
|
||||
}
|
||||
|
||||
#[group]
|
||||
#[commands(remux)]
|
||||
struct Transcode;
|
||||
|
||||
#[group]
|
||||
#[commands(ping)]
|
||||
struct General;
|
||||
|
||||
#[help]
|
||||
#[max_levenshtein_distance(2)]
|
||||
#[indention_prefix = "+"]
|
||||
@@ -56,8 +68,10 @@ async fn main() {
|
||||
};
|
||||
|
||||
let framework = StandardFramework::new()
|
||||
.configure(|c| c.owners(owners).prefix(","))
|
||||
.help(&MY_HELP);
|
||||
.configure(|c| c.owners(owners).prefix("xx"))
|
||||
.help(&MY_HELP)
|
||||
.group(&GENERAL_GROUP)
|
||||
.group(&TRANSCODE_GROUP);
|
||||
|
||||
let mut client = Client::builder(&token)
|
||||
.framework(framework)
|
||||
|
Reference in New Issue
Block a user