aboutsummaryrefslogtreecommitdiffstats
path: root/crates/yt_dlp/src
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2025-06-16 13:53:36 +0200
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2025-06-16 13:53:36 +0200
commitada9550b02ee13a8378bd2ee27d536b83eec4820 (patch)
treee59876669d3cc3bcec2a3b97f543c9a01ade321d /crates/yt_dlp/src
parentbuild(.envrc): Also disable ytdlp plugins by default (diff)
downloadyt-ada9550b02ee13a8378bd2ee27d536b83eec4820.zip
refactor(yt_dlp/lib): Explicitly convert python exceptions into an error
This avoids having to wrap all blocks into a `match` statement.
Diffstat (limited to 'crates/yt_dlp/src')
-rw-r--r--crates/yt_dlp/src/lib.rs89
1 files changed, 50 insertions, 39 deletions
diff --git a/crates/yt_dlp/src/lib.rs b/crates/yt_dlp/src/lib.rs
index 1f859fe..536b0d1 100644
--- a/crates/yt_dlp/src/lib.rs
+++ b/crates/yt_dlp/src/lib.rs
@@ -78,7 +78,7 @@ impl YoutubeDL {
///
/// # Errors
/// If a python call fails.
- pub fn from_options(mut options: YoutubeDLOptions) -> Result<Self, build::Error> {
+ pub fn from_options(options: YoutubeDLOptions) -> Result<Self, build::Error> {
let mut settings = vm::Settings::default();
if let Ok(python_path) = env::var("PYTHONPATH") {
for path in python_path.split(':') {
@@ -110,9 +110,8 @@ impl YoutubeDL {
let yt_dlp_module = vm.import("yt_dlp", 0)?;
let class = yt_dlp_module.get_attr("YoutubeDL", vm)?;
- let maybe_hook = mem::take(&mut options.progress_hook);
- let opts = options.into_py_dict(vm);
- if let Some(function) = maybe_hook {
+ let opts = json_loads(options.options, vm);
+ if let Some(function) = options.progress_hook {
opts.get_or_insert(vm, vm.new_pyobj("progress_hooks"), || {
let hook: PyObjectRef = vm.new_function("progress_hook", function).into();
vm.new_pyobj(vec![hook])
@@ -285,7 +284,7 @@ impl YoutubeDL {
download: bool,
process: bool,
) -> Result<InfoJson, extract_info::Error> {
- match self.interpreter.enter(|vm| {
+ self.interpreter.enter(|vm| {
let pos_args = PosArgs::new(vec![vm.new_pyobj(url.to_string())]);
let kw_args = KwArgs::new({
@@ -297,9 +296,13 @@ impl YoutubeDL {
let fun_args = FuncArgs::new(pos_args, kw_args);
- let inner = self.youtube_dl_class.get_attr("extract_info", vm)?;
+ let inner = self
+ .youtube_dl_class
+ .get_attr("extract_info", vm)
+ .map_err(|exc| PythonError::from_exception(vm, &exc))?;
let result = inner
- .call_with_args(fun_args, vm)?
+ .call_with_args(fun_args, vm)
+ .map_err(|exc| PythonError::from_exception(vm, &exc))?
.downcast::<PyDict>()
.expect("This is a dict");
@@ -313,7 +316,9 @@ impl YoutubeDL {
});
let mut out = vec![];
- let next = generator.get_attr("__next__", vm)?;
+ let next = generator
+ .get_attr("__next__", vm)
+ .map_err(|exc| PythonError::from_exception(vm, &exc))?;
while let Ok(output) = next.call((), vm) {
out.push(output);
@@ -321,7 +326,9 @@ impl YoutubeDL {
break;
}
}
- result.set_item("entries", vm.new_pyobj(out), vm)?;
+ result
+ .set_item("entries", vm.new_pyobj(out), vm)
+ .map_err(|exc| PythonError::from_exception(vm, &exc))?;
}
}
@@ -334,14 +341,8 @@ impl YoutubeDL {
let result_json = json_dumps(result, vm);
- Ok::<_, PyRef<PyBaseException>>(result_json)
- }) {
- Ok(ok) => Ok(ok),
- Err(err) => self.interpreter.enter(|vm| {
- let buffer = process_exception(vm, &err);
- Err(extract_info::Error::Python(buffer))
- }),
- }
+ Ok(result)
+ })
}
/// Take the (potentially modified) result of the information extractor (i.e.,
@@ -362,7 +363,7 @@ impl YoutubeDL {
ie_result: InfoJson,
download: bool,
) -> Result<InfoJson, process_ie_result::Error> {
- match self.interpreter.enter(|vm| {
+ self.interpreter.enter(|vm| {
let pos_args = PosArgs::new(vec![vm.new_pyobj(json_loads(ie_result, vm))]);
let kw_args = KwArgs::new({
@@ -373,9 +374,13 @@ impl YoutubeDL {
let fun_args = FuncArgs::new(pos_args, kw_args);
- let inner = self.youtube_dl_class.get_attr("process_ie_result", vm)?;
+ let inner = self
+ .youtube_dl_class
+ .get_attr("process_ie_result", vm)
+ .map_err(|exc| PythonError::from_exception(vm, &exc))?;
let result = inner
- .call_with_args(fun_args, vm)?
+ .call_with_args(fun_args, vm)
+ .map_err(|exc| PythonError::from_exception(vm, &exc))?
.downcast::<PyDict>()
.expect("This is a dict");
@@ -385,34 +390,47 @@ impl YoutubeDL {
value.downcast::<PyDict>().expect("This should stay a dict")
};
+ Ok(result)
+ })
+ }
- let result_json = json_dumps(result, vm);
- Ok::<_, PyRef<PyBaseException>>(result_json)
- }) {
- Ok(ok) => Ok(ok),
- Err(err) => self.interpreter.enter(|vm| {
- let buffer = process_exception(vm, &err);
- Err(process_ie_result::Error::Python(buffer))
- }),
}
+
+#[derive(thiserror::Error, Debug)]
+pub struct PythonError(pub String);
+
+impl Display for PythonError {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "Python threw an exception: {}", self.0)
+ }
+}
+
+impl PythonError {
+ fn from_exception(vm: &VirtualMachine, exc: &PyRef<PyBaseException>) -> Self {
+ let buffer = process_exception(vm, exc);
+ Self(buffer)
}
}
#[allow(missing_docs)]
pub mod process_ie_result {
+ use crate::{PythonError, prepare};
+
#[derive(Debug, thiserror::Error)]
pub enum Error {
- #[error("Python threw an exception: {0}")]
- Python(String),
+ #[error(transparent)]
+ Python(#[from] PythonError),
}
}
#[allow(missing_docs)]
pub mod extract_info {
+ use crate::{PythonError};
+
#[derive(Debug, thiserror::Error)]
pub enum Error {
- #[error("Python threw an exception: {0}")]
- Python(String),
+ #[error(transparent)]
+ Python(#[from] PythonError),
}
}
@@ -480,10 +498,6 @@ impl YoutubeDLOptions {
pub fn get(&self, key: &str) -> Option<&serde_json::Value> {
self.options.get(key)
}
-
- fn into_py_dict(self, vm: &VirtualMachine) -> PyRef<PyDict> {
- json_loads(self.options, vm)
- }
}
#[allow(missing_docs)]
@@ -492,9 +506,6 @@ pub mod build {
pub enum Error {
#[error("Python threw an exception: {0}")]
Python(String),
-
- #[error("Io error: {0}")]
- Io(#[from] std::io::Error),
}
}