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; {
|
devShells = with pkgs; {
|
||||||
default = mkShell
|
default = mkShell
|
||||||
{
|
{
|
||||||
buildInputs = [
|
buildInputs = with gst_all_1; [
|
||||||
rust-bin.nightly.latest.default
|
rust-bin.nightly.latest.default
|
||||||
rust-analyzer
|
rust-analyzer
|
||||||
|
ffmpeg
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
bare = mkShell
|
bare = mkShell
|
||||||
@@ -47,6 +48,9 @@
|
|||||||
nativeBuildInputs = with pkgs; [
|
nativeBuildInputs = with pkgs; [
|
||||||
rust-bin.nightly.latest.default
|
rust-bin.nightly.latest.default
|
||||||
];
|
];
|
||||||
|
buildInputs = with pkgs; [
|
||||||
|
ffmpeg
|
||||||
|
];
|
||||||
cargoSha256 = "sha256-DhWWUNDpDsao6lOogoM5UfUgrUfEmZvCpY0pxmr4/mI=";
|
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 handler;
|
||||||
|
mod lib;
|
||||||
|
use commands::general::*;
|
||||||
|
use commands::transcode::*;
|
||||||
use handler::Handler;
|
use handler::Handler;
|
||||||
use serenity::{
|
use serenity::{
|
||||||
client::bridge::gateway::ShardManager,
|
client::bridge::gateway::ShardManager,
|
||||||
framework::{
|
framework::{
|
||||||
standard::{
|
standard::{
|
||||||
help_commands,
|
help_commands,
|
||||||
macros::help,
|
macros::{group, help},
|
||||||
Args, CommandGroup, CommandResult, HelpOptions,
|
Args, CommandGroup, CommandResult, HelpOptions,
|
||||||
},
|
},
|
||||||
StandardFramework,
|
StandardFramework,
|
||||||
@@ -22,6 +26,14 @@ impl TypeMapKey for ShardManagerContainer {
|
|||||||
type Value = Arc<Mutex<ShardManager>>;
|
type Value = Arc<Mutex<ShardManager>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[group]
|
||||||
|
#[commands(remux)]
|
||||||
|
struct Transcode;
|
||||||
|
|
||||||
|
#[group]
|
||||||
|
#[commands(ping)]
|
||||||
|
struct General;
|
||||||
|
|
||||||
#[help]
|
#[help]
|
||||||
#[max_levenshtein_distance(2)]
|
#[max_levenshtein_distance(2)]
|
||||||
#[indention_prefix = "+"]
|
#[indention_prefix = "+"]
|
||||||
@@ -56,8 +68,10 @@ async fn main() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let framework = StandardFramework::new()
|
let framework = StandardFramework::new()
|
||||||
.configure(|c| c.owners(owners).prefix(","))
|
.configure(|c| c.owners(owners).prefix("xx"))
|
||||||
.help(&MY_HELP);
|
.help(&MY_HELP)
|
||||||
|
.group(&GENERAL_GROUP)
|
||||||
|
.group(&TRANSCODE_GROUP);
|
||||||
|
|
||||||
let mut client = Client::builder(&token)
|
let mut client = Client::builder(&token)
|
||||||
.framework(framework)
|
.framework(framework)
|
||||||
|
Reference in New Issue
Block a user