diff options
Diffstat (limited to 'crates/yt_dlp/src/lib.rs')
-rw-r--r-- | crates/yt_dlp/src/lib.rs | 67 |
1 files changed, 46 insertions, 21 deletions
diff --git a/crates/yt_dlp/src/lib.rs b/crates/yt_dlp/src/lib.rs index f958895..4e35cb0 100644 --- a/crates/yt_dlp/src/lib.rs +++ b/crates/yt_dlp/src/lib.rs @@ -8,6 +8,10 @@ // You should have received a copy of the License along with this program. // If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>. +// The pyo3 `pyfunction` proc-macros call unsafe functions internally, which trigger this lint. +#![allow(unsafe_op_in_unsafe_fn)] +#![allow(clippy::missing_errors_doc)] + use std::env; use std::{fs::File, io::Write}; @@ -31,14 +35,20 @@ pub mod duration; pub mod logging; pub mod wrapper; +#[cfg(test)] +mod tests; + /// Synchronisation helper, to ensure that we don't setup the logger multiple times static SYNC_OBJ: Once = Once::new(); /// Add a logger to the yt-dlp options. /// If you have an logger set (i.e. for rust), than this will log to rust +/// +/// # Panics +/// This should never panic. pub fn add_logger_and_sig_handler<'a>( opts: Bound<'a, PyDict>, - py: Python, + py: Python<'_>, ) -> PyResult<Bound<'a, PyDict>> { setup_logging(py, "yt_dlp")?; @@ -52,10 +62,9 @@ pub fn add_logger_and_sig_handler<'a>( // This allows the user to actually stop the application with Ctrl+C. // This is here because it can only be run in the main thread and this was here already. py.run_bound( - r#" + "\ import signal -signal.signal(signal.SIGINT, signal.SIG_DFL) - "#, +signal.signal(signal.SIGINT, signal.SIG_DFL)", None, None, ) @@ -82,14 +91,22 @@ signal.signal(signal.SIGINT, signal.SIG_DFL) } #[pyfunction] -pub fn progress_hook(py: Python, input: Bound<'_, PyDict>) -> PyResult<()> { +#[allow(clippy::too_many_lines)] +#[allow(clippy::missing_panics_doc)] +#[allow(clippy::items_after_statements)] +#[allow( + clippy::cast_possible_truncation, + clippy::cast_sign_loss, + clippy::cast_precision_loss +)] +pub fn progress_hook(py: Python<'_>, input: &Bound<'_, PyDict>) -> PyResult<()> { // Only add the handler, if the log-level is higher than Debug (this avoids covering debug // messages). if log_enabled!(Level::Debug) { return Ok(()); } - let input: serde_json::Map<String, Value> = serde_json::from_str(&json_dumps( + let input: Map<String, Value> = serde_json::from_str(&json_dumps( py, input .downcast::<PyAny>() @@ -164,8 +181,9 @@ pub fn progress_hook(py: Python, input: Bound<'_, PyDict>) -> PyResult<()> { } fn format_speed(speed: f64) -> String { + #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] let bytes = Bytes::new(speed.floor() as u64); - format!("{}/s", bytes) + format!("{bytes}/s") } let get_title = |add_extension: bool| -> String { @@ -187,7 +205,7 @@ pub fn progress_hook(py: Python, input: Bound<'_, PyDict>) -> PyResult<()> { default_get! { as_str, "<No title>", "info_dict", "title"}.to_owned() } } - other => panic!("The extension '{}' is not yet implemented", other), + other => panic!("The extension '{other}' is not yet implemented"), } }; @@ -242,18 +260,18 @@ pub fn progress_hook(py: Python, input: Bound<'_, PyDict>) -> PyResult<()> { ); } "finished" => { - println!("Finished downloading: '{}'", c!("34;1", get_title(false))) + println!("Finished downloading: '{}'", c!("34;1", get_title(false))); } "error" => { panic!("Error whilst downloading: {}", get_title(true)) } - other => panic!("{} is not a valid state!", other), + other => panic!("{other} is not a valid state!"), }; Ok(()) } -pub fn add_hooks<'a>(opts: Bound<'a, PyDict>, py: Python) -> PyResult<Bound<'a, PyDict>> { +pub fn add_hooks<'a>(opts: Bound<'a, PyDict>, py: Python<'_>) -> PyResult<Bound<'a, PyDict>> { if let Some(hooks) = opts.get_item("progress_hooks")? { let hooks = hooks.downcast::<PyList>()?; hooks.append(wrap_pyfunction_bound!(progress_hook, py)?)?; @@ -280,10 +298,12 @@ pub fn add_hooks<'a>(opts: Bound<'a, PyDict>, py: Python) -> PyResult<Bound<'a, /// @param download Whether to download videos /// @param process Whether to resolve all unresolved references (URLs, playlist items). /// Must be True for download to work -/// @param ie_key Use only the extractor with this key +/// @param `ie_key` Use only the extractor with this key /// -/// @param extra_info Dictionary containing the extra values to add to the info (For internal use only) -/// @force_generic_extractor Force using the generic extractor (Deprecated; use ie_key='Generic') +/// @param `extra_info` Dictionary containing the extra values to add to the info (For internal use only) +/// @`force_generic_extractor` Force using the generic extractor (Deprecated; use `ie_key`='Generic') +#[allow(clippy::unused_async)] +#[allow(clippy::missing_panics_doc)] pub async fn extract_info( yt_dlp_opts: &Map<String, Value>, url: &Url, @@ -311,8 +331,8 @@ pub async fn extract_info( if let Ok(confirm) = env::var("YT_STORE_INFO_JSON") { if confirm == "yes" { - let mut file = File::create("output.info.json").unwrap(); - write!(file, "{}", result_str).unwrap(); + let mut file = File::create("output.info.json")?; + write!(file, "{result_str}").unwrap(); } } @@ -321,7 +341,9 @@ pub async fn extract_info( }) } -pub fn unsmuggle_url(smug_url: Url) -> PyResult<Url> { +/// # Panics +/// Only if python fails to return a valid URL. +pub fn unsmuggle_url(smug_url: &Url) -> PyResult<Url> { Python::with_gil(|py| { let utils = get_yt_dlp_utils(py)?; let url = utils @@ -341,6 +363,9 @@ pub fn unsmuggle_url(smug_url: Url) -> PyResult<Url> { /// Download a given list of URLs. /// Returns the paths they were downloaded to. +/// +/// # Panics +/// Only if `yt_dlp` changes their `info_json` schema. pub async fn download( urls: &[Url], download_options: &Map<String, Value>, @@ -357,7 +382,7 @@ pub async fn download( } else { info_json.requested_downloads.expect("This must exist")[0] .filename - .to_owned() + .clone() }; out_paths.push(result_string); @@ -378,7 +403,7 @@ fn json_map_to_py_dict<'a>( Ok(python_dict) } -fn json_dumps(py: Python, input: Bound<PyAny>) -> PyResult<String> { +fn json_dumps(py: Python<'_>, input: Bound<'_, PyAny>) -> PyResult<String> { // json.dumps(yt_dlp.sanitize_info(input)) let yt_dlp = get_yt_dlp(py, PyDict::new_bound(py))?; @@ -394,13 +419,13 @@ fn json_dumps(py: Python, input: Bound<PyAny>) -> PyResult<String> { Ok(output_str) } -fn json_loads_str<T: Serialize>(py: Python, input: T) -> PyResult<Bound<PyDict>> { +fn json_loads_str<T: Serialize>(py: Python<'_>, input: T) -> PyResult<Bound<'_, PyDict>> { let string = serde_json::to_string(&input).expect("Correct json must be pased"); json_loads(py, string) } -fn json_loads(py: Python, input: String) -> PyResult<Bound<PyDict>> { +fn json_loads(py: Python<'_>, input: String) -> PyResult<Bound<'_, PyDict>> { // json.loads(input) let json = PyModule::import_bound(py, "json")?; |