make separate process spawn function with error types to avoid code duplication
This commit is contained in:
parent
494c00a60e
commit
b188551885
4 changed files with 89 additions and 75 deletions
|
|
@ -1,2 +1,3 @@
|
||||||
|
pub mod ffmpeg;
|
||||||
|
mod spawn;
|
||||||
pub mod yt_dlp;
|
pub mod yt_dlp;
|
||||||
pub mod ffmpeg;
|
|
||||||
|
|
@ -1,50 +1,27 @@
|
||||||
use core::fmt;
|
use super::spawn::{spawn, SpawnError};
|
||||||
use std::{path::Path, str::Utf8Error};
|
|
||||||
use tokio::process::Command;
|
|
||||||
|
|
||||||
pub enum FFMpegError {
|
|
||||||
CommandError(std::io::Error),
|
|
||||||
UtfError(Utf8Error),
|
|
||||||
ErrorMessage(String)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<std::io::Error> for FFMpegError {
|
|
||||||
fn from(value: std::io::Error) -> Self {
|
|
||||||
Self::CommandError(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Utf8Error> for FFMpegError {
|
|
||||||
fn from(value: Utf8Error) -> Self {
|
|
||||||
Self::UtfError(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for FFMpegError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
use FFMpegError as FE;
|
|
||||||
match self {
|
|
||||||
FE::CommandError(e) => write!(f, "Command::new - {}", e),
|
|
||||||
FE::UtfError(_) => write!(f, "Error while decoding UTF8"),
|
|
||||||
FE::ErrorMessage(msg) => write!(f, "ffmpeg error - {}", msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct FFMpeg {}
|
pub struct FFMpeg {}
|
||||||
|
|
||||||
impl FFMpeg {
|
impl FFMpeg {
|
||||||
pub async fn convert_to_mp3(input_path: &str, output_path: &str, bitrate: u16) -> Result<(), FFMpegError> {
|
pub async fn convert_to_mp3(
|
||||||
let output = Command::new("ffmpeg")
|
input_path: &str,
|
||||||
.args(["-i", input_path, "-codec:a", "libmp3lame", "-b:a", "32k", output_path])
|
output_path: &str,
|
||||||
.output()
|
bitrate: u16,
|
||||||
.await?;
|
) -> Result<(), SpawnError> {
|
||||||
|
let output = spawn(
|
||||||
|
"ffmpeg",
|
||||||
|
[
|
||||||
|
"-i",
|
||||||
|
input_path,
|
||||||
|
"-codec:a",
|
||||||
|
"libmp3lame",
|
||||||
|
"-b:a",
|
||||||
|
"32k",
|
||||||
|
output_path,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
if !output.status.success() {
|
|
||||||
let message = std::str::from_utf8(&output.stderr)?;
|
|
||||||
return Err(FFMpegError::ErrorMessage(message.to_string()));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
50
src/dl/spawn.rs
Normal file
50
src/dl/spawn.rs
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
use core::fmt;
|
||||||
|
use std::ffi::OsStr;
|
||||||
|
use std::process::Output;
|
||||||
|
use std::str::Utf8Error;
|
||||||
|
use tokio::process::Command;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum SpawnError {
|
||||||
|
CommandError(std::io::Error),
|
||||||
|
UtfError(Utf8Error),
|
||||||
|
ErrorMessage(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<std::io::Error> for SpawnError {
|
||||||
|
fn from(value: std::io::Error) -> Self {
|
||||||
|
Self::CommandError(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Utf8Error> for SpawnError {
|
||||||
|
fn from(value: Utf8Error) -> Self {
|
||||||
|
Self::UtfError(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for SpawnError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
use SpawnError as FE;
|
||||||
|
match self {
|
||||||
|
FE::CommandError(e) => write!(f, "Command::new - {}", e),
|
||||||
|
FE::UtfError(_) => write!(f, "Error while decoding UTF8"),
|
||||||
|
FE::ErrorMessage(msg) => write!(f, "ffmpeg error - {}", msg),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn spawn<I, S>(program: &str, args: I) -> Result<Output, SpawnError>
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = S>,
|
||||||
|
S: AsRef<OsStr>,
|
||||||
|
{
|
||||||
|
let output = Command::new(program).args(args).output().await?;
|
||||||
|
|
||||||
|
if !output.status.success() {
|
||||||
|
let message = std::str::from_utf8(&output.stderr)?;
|
||||||
|
return Err(SpawnError::ErrorMessage(message.to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(output)
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
|
use super::spawn::{spawn, SpawnError};
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
use ordered_float::OrderedFloat;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
use std::str::Utf8Error;
|
|
||||||
use tokio::process::Command;
|
|
||||||
use ordered_float::OrderedFloat;
|
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
pub struct YtDlpFormat {
|
pub struct YtDlpFormat {
|
||||||
|
|
@ -27,7 +26,7 @@ struct VideoFormat<'a> {
|
||||||
|
|
||||||
struct AudioFormat<'a> {
|
struct AudioFormat<'a> {
|
||||||
pub format: &'a YtDlpFormat,
|
pub format: &'a YtDlpFormat,
|
||||||
pub abr: f32
|
pub abr: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl YtDlpFormat {
|
impl YtDlpFormat {
|
||||||
|
|
@ -103,7 +102,7 @@ impl YtDlpInfo {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.max_by_key(|f| (f.width, f.height));
|
.max_by_key(|f| (f.width, f.height));
|
||||||
|
|
||||||
match format {
|
match format {
|
||||||
Some(vf) => Some(vf.format),
|
Some(vf) => Some(vf.format),
|
||||||
None => None,
|
None => None,
|
||||||
|
|
@ -114,9 +113,14 @@ impl YtDlpInfo {
|
||||||
let format = self
|
let format = self
|
||||||
.formats
|
.formats
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|f| Some(AudioFormat { format: f, abr: f.abr? }))
|
.filter_map(|f| {
|
||||||
|
Some(AudioFormat {
|
||||||
|
format: f,
|
||||||
|
abr: f.abr?,
|
||||||
|
})
|
||||||
|
})
|
||||||
.max_by_key(|f| OrderedFloat(f.abr));
|
.max_by_key(|f| OrderedFloat(f.abr));
|
||||||
|
|
||||||
match format {
|
match format {
|
||||||
Some(af) => Some(af.format),
|
Some(af) => Some(af.format),
|
||||||
None => None,
|
None => None,
|
||||||
|
|
@ -126,21 +130,13 @@ impl YtDlpInfo {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum YtDlpError {
|
pub enum YtDlpError {
|
||||||
CommandError(std::io::Error),
|
SpawnError(SpawnError),
|
||||||
UtfError(Utf8Error),
|
|
||||||
ErrorMessage(String),
|
|
||||||
JsonError,
|
JsonError,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<std::io::Error> for YtDlpError {
|
impl From<SpawnError> for YtDlpError {
|
||||||
fn from(value: std::io::Error) -> Self {
|
fn from(value: SpawnError) -> Self {
|
||||||
Self::CommandError(value)
|
Self::SpawnError(value)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Utf8Error> for YtDlpError {
|
|
||||||
fn from(value: Utf8Error) -> Self {
|
|
||||||
Self::UtfError(value)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -154,9 +150,7 @@ impl fmt::Display for YtDlpError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
use YtDlpError as YTE;
|
use YtDlpError as YTE;
|
||||||
match self {
|
match self {
|
||||||
YTE::CommandError(e) => write!(f, "Command::new - {}", e),
|
YTE::SpawnError(e) => write!(f, "{}", e),
|
||||||
YTE::UtfError(_) => write!(f, "Error while decoding UTF8"),
|
|
||||||
YTE::ErrorMessage(msg) => write!(f, "yt-dlp error - {}", msg),
|
|
||||||
YTE::JsonError => write!(f, "json parsing error"),
|
YTE::JsonError => write!(f, "json parsing error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -166,15 +160,7 @@ pub struct YtDlp {}
|
||||||
|
|
||||||
impl YtDlp {
|
impl YtDlp {
|
||||||
pub async fn load_info(url: &str) -> Result<YtDlpInfo, YtDlpError> {
|
pub async fn load_info(url: &str) -> Result<YtDlpInfo, YtDlpError> {
|
||||||
let output = Command::new("python")
|
let output = spawn("python", ["-m", "yt_dlp", url, "-j"]).await?;
|
||||||
.args(["-m", "yt_dlp", url, "-j"])
|
|
||||||
.output()
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
if !output.status.success() {
|
|
||||||
let message = std::str::from_utf8(&output.stderr)?;
|
|
||||||
return Err(YtDlpError::ErrorMessage(message.to_string()));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(YtDlpInfo::parse(&output.stdout)?)
|
Ok(YtDlpInfo::parse(&output.stdout)?)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue