daniel-e / captcha

CAPTCHA library written in Rust.
MIT License
98 stars 20 forks source link

Feature request, audio generation. #5

Closed dessalines closed 4 years ago

dessalines commented 4 years ago

Obvi I understand if this would be better as a part of a different library, but to make this crate visually-impaired compatible, it would be good if it could also generate a short audio file along with the picture. No captcha solution is complete without audio.

dessalines commented 4 years ago

I recently added this to lemmy in https://github.com/LemmyNet/lemmy/pull/1027

If anyone's interested in a quick way to do this, here's the relevant code:

pub fn captcha_espeak_wav_base64(captcha: &str) -> Result<String, LemmyError> {
  let mut built_text = String::new();

  // Building proper speech text for espeak
  for mut c in captcha.chars() {
    let new_str = if c.is_alphabetic() {
      if c.is_lowercase() {
        c.make_ascii_uppercase();
        format!("lower case {} ... ", c)
      } else {
        c.make_ascii_uppercase();
        format!("capital {} ... ", c)
      }
    } else {
      format!("{} ...", c)
    };

    built_text.push_str(&new_str);
  }

  espeak_wav_base64(&built_text)
}

pub fn espeak_wav_base64(text: &str) -> Result<String, LemmyError> {
  // Make a temp file path
  let uuid = uuid::Uuid::new_v4().to_string();
  let file_path = format!("/tmp/lemmy_espeak_{}.wav", &uuid);

  // Write the wav file
  Command::new("espeak")
    .arg("-w")
    .arg(&file_path)
    .arg(text)
    .status()?;

  // Read the wav file bytes
  let bytes = std::fs::read(&file_path)?;

  // Delete the file
  std::fs::remove_file(file_path)?;

  // Convert to base64
  let base64 = base64::encode(bytes);

  Ok(base64)
}
daniel-e commented 4 years ago

Hi @dessalines thank you for your feature request and your example code. I now have implemented audio generation. I have improved your suggestion a bit:

An example is in the example directory.

dessalines commented 4 years ago

Sounds good, I'll watch the repo for the next release which includes this, thanks!

daniel-e commented 4 years ago

Just published the new version to crates.io.

dessalines commented 2 years ago

https://github.com/LemmyNet/lemmy-ui/issues/514

Is hound adding a "end of wav file" thing to each letter? Since I've started using this, chromium and safari, when listening to a base64 encoded wave file, only plays the first letter, then stops abruptly before the full duration. The full playback works on firefox.

Here's my converting code, which works fine in FF but not chrome. Makes me think the full appended bytes are malformed in some way, that FF is able to push through.

pub(crate) fn captcha_as_wav_base64(captcha: &Captcha) -> String {
  let letters = captcha.as_wav();

  let mut concat_letters: Vec<u8> = Vec::new();

  for letter in letters {
    let bytes = letter.unwrap_or_default();
    concat_letters.extend(bytes);
  }

  // Convert to base64
  base64::encode(concat_letters)
}