CLI utility to ingest embedded json metadata from yt-dlp downloads to a SQLite database file
yt-dlp
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

refactor: Switch from `anyhow` to `thiserror`

0xBA5E64 428931de 0dd1541f

+51 -36
+22 -9
Cargo.lock
··· 1 1 # This file is automatically @generated by Cargo. 2 2 # It is not intended for manual editing. 3 - version = 3 3 + version = 4 4 4 5 5 [[package]] 6 6 name = "anstream" ··· 50 50 "anstyle", 51 51 "windows-sys", 52 52 ] 53 - 54 - [[package]] 55 - name = "anyhow" 56 - version = "1.0.93" 57 - source = "registry+https://github.com/rust-lang/crates.io-index" 58 - checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" 59 53 60 54 [[package]] 61 55 name = "bitstream-io" ··· 280 274 ] 281 275 282 276 [[package]] 277 + name = "thiserror" 278 + version = "2.0.18" 279 + source = "registry+https://github.com/rust-lang/crates.io-index" 280 + checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" 281 + dependencies = [ 282 + "thiserror-impl", 283 + ] 284 + 285 + [[package]] 286 + name = "thiserror-impl" 287 + version = "2.0.18" 288 + source = "registry+https://github.com/rust-lang/crates.io-index" 289 + checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" 290 + dependencies = [ 291 + "proc-macro2", 292 + "quote", 293 + "syn", 294 + ] 295 + 296 + [[package]] 283 297 name = "unicode-ident" 284 298 version = "1.0.13" 285 299 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 368 382 name = "ydjr" 369 383 version = "0.1.0" 370 384 dependencies = [ 371 - "anyhow", 372 385 "clap", 373 386 "matroska", 374 - "serde", 375 387 "serde_json", 388 + "thiserror", 376 389 ]
+1 -2
Cargo.toml
··· 4 4 edition = "2021" 5 5 6 6 [dependencies] 7 - anyhow = "1.0.93" 8 7 clap = { version = "4.5.21", features = ["derive"] } 9 8 matroska = "0.28.0" 10 - serde = "1.0.215" 11 9 serde_json = "1.0.132" 10 + thiserror = "2.0.18"
+26 -23
src/lib.rs
··· 1 - use std::{fs, path::PathBuf}; 1 + use std::{fs, io, path::PathBuf}; 2 + use std::fs::DirEntry; 3 + use thiserror::Error; 2 4 3 - use anyhow::{Context, Error, anyhow, Result}; 5 + #[derive(Error, Debug)] 6 + pub enum ExtractError { 7 + #[error("Failed to open file")] 8 + FileOpenError, 9 + #[error("Failed to parse file")] 10 + FileParseError, 11 + #[error("Failed to parse json")] 12 + JsonParseError 13 + } 4 14 5 - fn extract_json_metadata(file: &PathBuf) -> Result<serde_json::Value> { 15 + fn extract_json_metadata(file: &PathBuf) -> Result<serde_json::Value, ExtractError> { 6 16 // Parse the Matroska file 7 17 let matroska = 8 - matroska::open(file).context(format!("Unable to parse Matroska file: {:?}", file))?; 18 + matroska::open(file).map_err(|_| ExtractError::FileParseError)?; 9 19 // Find the json attachment 10 20 let json_attachment = matroska 11 21 .attachments 12 22 .into_iter() 13 - .find(|x| x.name.ends_with(".json")) 14 - .ok_or(Error::msg(format!( 15 - "Unable to find JSON attachment in file: {:?}", 16 - file 17 - )))?; 23 + .find(|x| x.name.ends_with(".json")).ok_or(ExtractError::FileParseError)?; 24 + 18 25 // Parse it as JSON and return the result 19 26 serde_json::from_slice(&json_attachment.data) 20 - .map_err(anyhow::Error::from) 21 - .context(format!("Unable to parse JSON for file: {:?}", file)) 27 + .map_err(|_| ExtractError::JsonParseError) 22 28 } 23 29 24 30 // Renames "file" to "new_name" without changing its directory 25 - fn rename_file(file: &PathBuf, new_name: &str) -> Result<()> { 31 + fn rename_file(file: &PathBuf, new_name: &str) -> io::Result<()> { 26 32 let mut new_path = file.clone(); 27 33 new_path.set_file_name(new_name); 28 34 fs::rename(file, new_path) 29 - .map_err(anyhow::Error::from) 30 - .context(format!("Unable to rename file {:?}", file)) 31 35 } 32 36 33 - pub fn rename_video(file: &PathBuf) -> Result<()> { 37 + pub fn rename_video(file: &PathBuf) -> io::Result<()> { 34 38 // Extract JSON metadata from video-file 35 - let json: serde_json::Value = extract_json_metadata(&file)?; 39 + let json: serde_json::Value = extract_json_metadata(&file).unwrap(); 36 40 37 41 // Construct new filename 38 42 let new_filename = format!( ··· 45 49 rename_file(&file, &new_filename) 46 50 } 47 51 48 - pub fn rename_videos(in_dir: PathBuf) -> Result<()> { 52 + pub fn rename_videos(in_dir: PathBuf) -> io::Result<()> { 49 53 50 54 let mut renamed_videos: Vec<PathBuf> = Vec::new(); 51 55 let mut failed_videos: Vec<PathBuf> = Vec::new(); 52 56 53 57 for entry in 54 58 // Iterator over all (valid) Entries in directory 55 - fs::read_dir(&in_dir).context(format!("Unable to read directory: {:?}", in_dir))? 59 + fs::read_dir(&in_dir)? 56 60 .flatten() 57 61 // Filter for mkv files 58 - .filter(|x| x.file_name().into_string().unwrap().ends_with(".mkv")) 62 + .filter(|x: &DirEntry| x.file_name().into_string().unwrap().ends_with(".mkv")) 59 63 // Unwrap the paths 60 - .map(|x| x.path()) 64 + .map(|x: DirEntry| x.path()) 61 65 { 62 66 match rename_video(&entry) { 63 67 Ok(_i) => renamed_videos.push(entry), ··· 66 70 } 67 71 68 72 if failed_videos.len() > 0 { 69 - Err(anyhow!(format!("{} files failed at renaming", failed_videos.len()))) 70 - } else { 71 - Ok(()) 73 + println!("Failed to be rename {} videos.", failed_videos.iter().count()); 72 74 } 75 + Ok(()) 73 76 }
+2 -2
src/main.rs
··· 1 1 use std::path::PathBuf; 2 + use std::io; 2 3 3 - use anyhow::Result; 4 4 use ydjr::*; 5 5 6 6 use clap::Parser; ··· 12 12 path: String, 13 13 } 14 14 15 - fn main() -> Result<()> { 15 + fn main() -> io::Result<()> { 16 16 let args = Args::parse(); 17 17 18 18 let dir = PathBuf::from(args.path);