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