commands/transcode: add speed command
This commit is contained in:
@@ -51,7 +51,7 @@
|
||||
buildInputs = with pkgs; [
|
||||
ffmpeg
|
||||
];
|
||||
cargoSha256 = "sha256-DhWWUNDpDsao6lOogoM5UfUgrUfEmZvCpY0pxmr4/mI=";
|
||||
cargoSha256 = "sha256-0rzz+xOQnZYwygReKobNvUAOMeRrFZj7FUVSkAObm7I=";
|
||||
};
|
||||
}
|
||||
);
|
||||
|
@@ -17,7 +17,7 @@ pub async fn remux(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
||||
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",
|
||||
"Please use the proper syntax: `xxremux <audio> <video> [audio_codec] [video_codec]`",
|
||||
)
|
||||
.await?;
|
||||
return Ok(());
|
||||
@@ -27,22 +27,27 @@ pub async fn remux(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
||||
|
||||
trans.add_input(q[0]);
|
||||
|
||||
trans.set_acodec("copy");
|
||||
|
||||
let mut ext = Path::new(&q[1]).extension().unwrap().to_str().unwrap();
|
||||
if IMAGE_EXTS.contains(&ext) {
|
||||
let resp = reqwest::get(q[1]).await?;
|
||||
let p = format!("/tmp/{}{}-image.{}", "singh4-", msg.id, ext);
|
||||
let mut f = File::create(&p).await?;
|
||||
tokio::io::copy(&mut resp.bytes().await?.as_ref(), &mut f).await?;
|
||||
if ext == "gif" {
|
||||
trans.add_flags(vec!["-stream_loop", "-1"]);
|
||||
} else {
|
||||
trans.add_arg("loop", 1u32);
|
||||
}
|
||||
trans
|
||||
.add_arg("loop", 1u32)
|
||||
.add_input(&p)
|
||||
.set_vcodec("h264")
|
||||
.add_arg("vf", "pad=ceil(iw/2)*2:ceil(ih/2)*2") //to correct the dimensions
|
||||
.add_arg("tune", "stillimage");
|
||||
|
||||
ext = "mp4";
|
||||
} else {
|
||||
trans.add_input(q[1]);
|
||||
trans.add_input(q[1]).set_vcodec("copy");
|
||||
}
|
||||
|
||||
if q.len() > 2 {
|
||||
@@ -76,7 +81,73 @@ pub async fn remux(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
||||
.send_message(ctx, |m| {
|
||||
m.add_file(AttachmentType::File {
|
||||
file: &file,
|
||||
filename: format!("{}.{}", msg.id, ext),
|
||||
filename: format!("{}.{}", msg.id, if ext.is_empty() { "mp4" } else { ext }),
|
||||
})
|
||||
.content(msg.author.mention())
|
||||
})
|
||||
.await?;
|
||||
}
|
||||
m.delete(ctx).await?;
|
||||
remove_file(output)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[command]
|
||||
#[aliases("sp")]
|
||||
pub async fn speed(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
|
||||
if (msg.attachments.len() == 0 && args.len() != 2)
|
||||
|| (msg.attachments.len() == 1 && args.len() != 1)
|
||||
{
|
||||
msg.reply(
|
||||
ctx,
|
||||
"Please use the proper syntax: `xxspeed <file> <speed_multiplier>`",
|
||||
)
|
||||
.await?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if msg.attachments.len() > 1 {
|
||||
msg.reply(ctx, "Please attach one file at a time").await?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let f: String = if msg.attachments.len() == 1 {
|
||||
msg.attachments[0].url.clone()
|
||||
} else {
|
||||
args.single::<String>().unwrap()
|
||||
};
|
||||
|
||||
let multiplier = args.single::<f32>().unwrap();
|
||||
let mut trans = FfmpegTranscode::default();
|
||||
|
||||
trans
|
||||
.add_input(&f)
|
||||
.add_vfilter(format!("setpts={}*PTS", 1f32 / multiplier))
|
||||
.add_afilter(format!("atempo={}", multiplier));
|
||||
|
||||
let mut ext = Path::new(&f).extension().unwrap().to_str().unwrap();
|
||||
let output = format!("/tmp/{}{}.{}", "singh4-", msg.id, ext);
|
||||
|
||||
trans.set_output(&output);
|
||||
|
||||
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.code().unwrap() != 0 {
|
||||
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, if ext.is_empty() { "mp4" } else { ext }),
|
||||
})
|
||||
.content(msg.author.mention())
|
||||
})
|
||||
|
@@ -15,8 +15,12 @@ fn sanitize_arg<V: Into<String>>(value: V) -> String {
|
||||
pub struct FfmpegTranscode {
|
||||
args: Vec<String>,
|
||||
out: String,
|
||||
acodec: String,
|
||||
vcodec: String,
|
||||
acodec: Option<String>,
|
||||
vcodec: Option<String>,
|
||||
abitrate: Option<String>,
|
||||
vbitrate: Option<String>,
|
||||
afilter: Vec<String>,
|
||||
vfilter: Vec<String>,
|
||||
}
|
||||
|
||||
impl Default for FfmpegTranscode {
|
||||
@@ -24,8 +28,12 @@ impl Default for FfmpegTranscode {
|
||||
FfmpegTranscode {
|
||||
args: vec![],
|
||||
out: String::from("/tmp/ffmpeg"),
|
||||
acodec: String::from("copy"),
|
||||
vcodec: String::from("copy"),
|
||||
acodec: None,
|
||||
vcodec: None,
|
||||
abitrate: None,
|
||||
vbitrate: None,
|
||||
afilter: vec![],
|
||||
vfilter: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -59,12 +67,48 @@ impl FfmpegTranscode {
|
||||
}
|
||||
|
||||
pub fn set_acodec<V: ToString>(&mut self, acodec: V) -> &mut Self {
|
||||
self.acodec = acodec.to_string();
|
||||
self.acodec = Some(acodec.to_string()).filter(String::is_empty);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_vcodec<V: ToString>(&mut self, vcodec: V) -> &mut Self {
|
||||
self.vcodec = vcodec.to_string();
|
||||
self.vcodec = Some(vcodec.to_string()).filter(String::is_empty);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_abitrate<V: ToString>(&mut self, bit: V) -> &mut Self {
|
||||
self.abitrate = Some(bit.to_string()).filter(String::is_empty);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_vbitrate<V: ToString>(&mut self, bit: V) -> &mut Self {
|
||||
self.vbitrate = Some(bit.to_string()).filter(String::is_empty);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_afilter<V: Into<String>>(&mut self, value: V) -> &mut Self {
|
||||
self.afilter.push(value.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_afilter<T: Into<String>, V: IntoIterator<Item = T>>(
|
||||
&mut self,
|
||||
value: V,
|
||||
) -> &mut Self {
|
||||
self.afilter = value.into_iter().map(|x| x.into()).collect();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_vfilter<V: Into<String>>(&mut self, value: V) -> &mut Self {
|
||||
self.vfilter.push(value.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_vfilter<T: Into<String>, V: IntoIterator<Item = T>>(
|
||||
&mut self,
|
||||
value: V,
|
||||
) -> &mut Self {
|
||||
self.vfilter = value.into_iter().map(|x| x.into()).collect();
|
||||
self
|
||||
}
|
||||
|
||||
@@ -74,12 +118,37 @@ impl FfmpegTranscode {
|
||||
|
||||
pub fn run(&self) -> ExitStatus {
|
||||
println!("{}", self.args.join(" "));
|
||||
|
||||
Command::new("ffmpeg")
|
||||
.args(&self.args)
|
||||
.args(vec!["-c:a", &self.acodec])
|
||||
.args(vec!["-c:v", &self.vcodec])
|
||||
.args(match &self.acodec {
|
||||
Some(ac) => vec!["-c:a", ac],
|
||||
None => vec![],
|
||||
})
|
||||
.args(match &self.vcodec {
|
||||
Some(vc) => vec!["-c:v", vc],
|
||||
None => vec![],
|
||||
})
|
||||
.args(match &self.abitrate {
|
||||
Some(ab) => vec!["-b:a", ab],
|
||||
None => vec![],
|
||||
})
|
||||
.args(match &self.vbitrate {
|
||||
Some(vb) => vec!["-b:v", vb],
|
||||
None => vec![],
|
||||
})
|
||||
.args(if !self.vfilter.is_empty() {
|
||||
vec![String::from("-filter:v"), self.vfilter.join(";")]
|
||||
} else {
|
||||
vec![]
|
||||
})
|
||||
.args(if !self.afilter.is_empty() {
|
||||
vec![String::from("-filter:a"), self.afilter.join(";")]
|
||||
} else {
|
||||
vec![]
|
||||
})
|
||||
.arg(&self.out)
|
||||
.status()
|
||||
.expect("FFmpeg failed to run")
|
||||
.expect("Can't execute ffmpeg")
|
||||
}
|
||||
}
|
||||
|
@@ -27,7 +27,7 @@ impl TypeMapKey for ShardManagerContainer {
|
||||
}
|
||||
|
||||
#[group]
|
||||
#[commands(remux)]
|
||||
#[commands(remux,speed)]
|
||||
struct Transcode;
|
||||
|
||||
#[group]
|
||||
|
Reference in New Issue
Block a user