mirror of
https://github.com/narrrl/ytd-rs.git
synced 2026-11-03 16:41:27 +01:00
added YoutubeDLError for better error handling
This commit is contained in:
1 parent
eacdceaaaf
commit
cfa2303d46
2 files changed
+69
-25
No files matched your search
@@ -8,7 +8,7 @@ use ytd_rs::{YoutubeDL, ResultType, Arg};
|
||||
// one doesn't take any input and is an option, the other takes the desired output format as input
|
||||
let args = vec![Arg::new("--quiet"), Arg::new_with_arg("--output", "%(title).90s.%(ext)s")];
|
||||
let link = "https://www.youtube.com/watch?v=uTO0KnDsVH0";
|
||||
let ytd = YoutubeDL::new("./path/to/download/directory", args, link).unwrap();
|
||||
let ytd = YoutubeDL::new("./path/to/download/directory", args, link)?;
|
||||
|
||||
// start download
|
||||
let download = ytd.download();
|
||||
|
||||
+68
-24
@@ -4,11 +4,15 @@
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use ytd_rs::{YoutubeDL, ResultType, Arg};
|
||||
//! use std::path::PathBuf;
|
||||
//! use std::error::Error;
|
||||
//! fn main() -> Result<(), Box<dyn Error>> {
|
||||
//! // youtube-dl arguments quietly run process and to format the output
|
||||
//! // one doesn't take any input and is an option, the other takes the desired output format as input
|
||||
//! let args = vec![Arg::new("--quiet"), Arg::new_with_arg("--output", "%(title).90s.%(ext)s")];
|
||||
//! let link = "https://www.youtube.com/watch?v=uTO0KnDsVH0";
|
||||
//! let ytd = YoutubeDL::new("./path/to/download/directory", args, link).unwrap();
|
||||
//! let path = PathBuf::from("./path/to/download/directory");
|
||||
//! let ytd = YoutubeDL::new(&path, args, link)?;
|
||||
//!
|
||||
//! // start download
|
||||
//! let download = ytd.download();
|
||||
@@ -19,20 +23,24 @@
|
||||
//! ResultType::IOERROR | ResultType::FAILURE =>
|
||||
//! println!("Couldn't start download: {}", download.output()),
|
||||
//! };
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
use std::{
|
||||
error::Error,
|
||||
fmt,
|
||||
process::{Output, Stdio},
|
||||
};
|
||||
use std::{
|
||||
fmt::{Display, Formatter},
|
||||
fs::{canonicalize, create_dir_all},
|
||||
io::Error,
|
||||
path::PathBuf,
|
||||
};
|
||||
use std::{path::Path, process::Command};
|
||||
|
||||
type Result<T> = std::result::Result<T, YoutubeDLError>;
|
||||
|
||||
/// A structure that represents an argument of a youtube-dl command.
|
||||
///
|
||||
/// There are two different kinds of Arg:
|
||||
@@ -82,6 +90,31 @@ impl Display for Arg {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct YoutubeDLError {
|
||||
message: String,
|
||||
}
|
||||
|
||||
impl YoutubeDLError {
|
||||
pub fn new(message: &str) -> YoutubeDLError {
|
||||
YoutubeDLError {
|
||||
message: message.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for YoutubeDLError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.message)
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for YoutubeDLError {
|
||||
fn description(&self) -> &str {
|
||||
self.message.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
/// Structure that represents a youtube-dl task.
|
||||
///
|
||||
/// Every task needs a download location, a list of ['Arg'] that can be empty
|
||||
@@ -108,9 +141,9 @@ pub struct YoutubeDLResult {
|
||||
|
||||
impl YoutubeDLResult {
|
||||
/// creates a new YoutubeDLResult
|
||||
fn new(path: PathBuf) -> YoutubeDLResult {
|
||||
fn new(path: &PathBuf) -> YoutubeDLResult {
|
||||
YoutubeDLResult {
|
||||
path,
|
||||
path: path.clone(),
|
||||
output: String::new(),
|
||||
kind: ResultType::FAILURE,
|
||||
}
|
||||
@@ -147,10 +180,10 @@ impl YoutubeDL {
|
||||
///
|
||||
/// The path gets canonicalized and the directory gets created by the constructor
|
||||
pub fn new_multiple_links(
|
||||
dl_path: &str,
|
||||
dl_path: &PathBuf,
|
||||
args: Vec<Arg>,
|
||||
links: Vec<String>,
|
||||
) -> Result<YoutubeDL, String> {
|
||||
) -> Result<YoutubeDL> {
|
||||
// create path
|
||||
let path = Path::new(dl_path);
|
||||
|
||||
@@ -158,34 +191,40 @@ impl YoutubeDL {
|
||||
if !path.exists() {
|
||||
// if not create
|
||||
if let Err(why) = create_dir_all(&path) {
|
||||
return Err(format!(
|
||||
return Err(YoutubeDLError::new(
|
||||
format!(
|
||||
"Error while creating directories {}: {:?}",
|
||||
dl_path, why
|
||||
dl_path.to_string_lossy(),
|
||||
why
|
||||
)
|
||||
.as_ref(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// return error if no directory
|
||||
if !path.is_dir() {
|
||||
return Err("Error: path is not a directory".to_string());
|
||||
return Err(YoutubeDLError::new("Error: path is not a directory"));
|
||||
}
|
||||
|
||||
// absolute path
|
||||
match canonicalize(dl_path) {
|
||||
// return new youtube-dl job
|
||||
Ok(path) => Ok(YoutubeDL { path, links, args }),
|
||||
Err(why) => Err(format!("Error creating YouTubeDL: {:?}", why)),
|
||||
Err(why) => Err(YoutubeDLError::new(
|
||||
format!("Error creating YouTubeDL: {:?}", why).as_ref(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(dl_path: &str, args: Vec<Arg>, link: &str) -> Result<YoutubeDL, String> {
|
||||
pub fn new(dl_path: &PathBuf, args: Vec<Arg>, link: &str) -> Result<YoutubeDL> {
|
||||
YoutubeDL::new_multiple_links(dl_path, args, vec![link.to_string()])
|
||||
}
|
||||
|
||||
/// Starts the download and returns when finished the result as [`YoutubeDLResult`].
|
||||
pub fn download(&self) -> YoutubeDLResult {
|
||||
let pr_result = self.spawn_youtube_dl();
|
||||
let mut result = YoutubeDLResult::new(self.path.clone());
|
||||
let mut result = YoutubeDLResult::new(&self.path);
|
||||
|
||||
let output = match pr_result {
|
||||
Err(why) => {
|
||||
@@ -206,7 +245,7 @@ impl YoutubeDL {
|
||||
result
|
||||
}
|
||||
|
||||
fn spawn_youtube_dl(&self) -> Result<Output, Error> {
|
||||
fn spawn_youtube_dl(&self) -> Result<Output> {
|
||||
let mut cmd = Command::new("youtube-dl");
|
||||
cmd.current_dir(&self.path)
|
||||
.env("LC_ALL", "en_US.UTF-8")
|
||||
@@ -226,11 +265,18 @@ impl YoutubeDL {
|
||||
|
||||
let pr = match cmd.spawn() {
|
||||
Err(why) => {
|
||||
return Err(why);
|
||||
return Err(YoutubeDLError::new(
|
||||
format!("Error, YoutubeDL exited with {:?}", why).as_ref(),
|
||||
));
|
||||
}
|
||||
Ok(process) => process,
|
||||
};
|
||||
pr.wait_with_output()
|
||||
match pr.wait_with_output() {
|
||||
Ok(output) => Ok(output),
|
||||
Err(why) => Err(YoutubeDLError::new(
|
||||
format!("Error, YoutubeDL exited with {:?}", why).as_ref(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,27 +284,25 @@ impl YoutubeDL {
|
||||
mod tests {
|
||||
use crate::{Arg, YoutubeDL};
|
||||
use regex::Regex;
|
||||
use std::env;
|
||||
use std::{env, error::Error};
|
||||
|
||||
#[test]
|
||||
fn version() {
|
||||
fn version() -> Result<(), Box<dyn Error>> {
|
||||
let current_dir = env::current_dir()?;
|
||||
let ytd = YoutubeDL::new(
|
||||
env::current_dir()
|
||||
.expect("couldn't get working directory")
|
||||
.to_str()
|
||||
.unwrap(),
|
||||
¤t_dir,
|
||||
// get youtube-dl version
|
||||
vec![Arg::new("--version")],
|
||||
// we don't need a link to print version
|
||||
"",
|
||||
)
|
||||
.expect("Couldn't create youtube-dl");
|
||||
)?;
|
||||
|
||||
let regex = Regex::new(r"\d{4}\.\d{2}\.\d{2}").unwrap();
|
||||
let regex = Regex::new(r"\d{4}\.\d{2}\.\d{2}")?;
|
||||
let output = ytd.download();
|
||||
|
||||
// check output
|
||||
// fails if youtube-dl is not installed
|
||||
assert!(regex.is_match(output.output()));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user