From 598ee0199a50d30d06f4a2fa67bed5943c6452b4 Mon Sep 17 00:00:00 2001 From: A Farzat Date: Thu, 5 Mar 2026 16:21:38 +0300 Subject: Deserialize URLs to Url type directly This saves the effort of having to do it manually later on. Also avoids duplication in parsing. --- Cargo.lock | 2 ++ Cargo.toml | 1 + src/epub.rs | 19 ++++++------------- src/models.rs | 3 ++- 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c546287..9417be2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -860,6 +860,7 @@ dependencies = [ "serde", "serde_json", "tokio", + "url", "zip", ] @@ -1663,6 +1664,7 @@ dependencies = [ "idna", "percent-encoding", "serde", + "serde_derive", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 89d5c73..dbe5793 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,4 +11,5 @@ reqwest = { version = "0.13.2", features = ["cookies", "json"] } serde = { version = "1.0.228", features = ["derive"] } serde_json = "1.0.149" tokio = { version = "1.49.0", features = ["full"] } +url = { version = "2.5.8", features = ["serde"] } zip = { version = "8.1.0", default-features = false, features = ["deflate"] } diff --git a/src/epub.rs b/src/epub.rs index b995767..406135b 100644 --- a/src/epub.rs +++ b/src/epub.rs @@ -1,7 +1,7 @@ use crate::models::{Chapter, FileEntry}; use anyhow::{Context, Result}; use relative_path::{RelativePath, RelativePathBuf}; -use reqwest::{Client, Url}; +use reqwest::Client; use std::{ collections::HashMap, io::{Read, Write}, @@ -51,7 +51,7 @@ pub async fn download_all_files( let mut file = File::create(dest_path).await?; let bytes = client - .get(&entry.url) + .get(entry.url.clone()) .send() .await? .error_for_status()? @@ -87,10 +87,10 @@ pub fn create_epub_archive( write_container_xml_to_zip(&mut zip, &opf_entry.full_path)?; // Prepare url path to local path mapping to clean xhtml files from external dependencies. - let url_to_local = file_entries + let url_path_to_local = file_entries .iter() - .map(url_path_to_local) - .collect::>>()?; + .map(|e| (e.url.path(), &e.full_path)) + .collect::>(); // Add the rest of the files according to file_entries. let options: FileOptions<()> = @@ -103,7 +103,7 @@ pub fn create_epub_archive( if chapters.contains_key(&entry.ourn) { let mut html = String::from_utf8(buffer)?; let chapter_dir = entry.full_path.parent().unwrap_or(RelativePath::new("")); - for (url_path, local_path) in &url_to_local { + for (url_path, local_path) in &url_path_to_local { let rel_path = chapter_dir.relative(local_path); html = html.replace(url_path, rel_path.as_str()); } @@ -117,10 +117,3 @@ pub fn create_epub_archive( Ok(()) } - -/// Helper function. Maps FileEntry to (url path, full_path) pair. -fn url_path_to_local(entry: &FileEntry) -> Result<(String, RelativePathBuf)> { - let url = Url::parse(&entry.url).with_context(|| format!("Could not parse: {}", entry.url))?; - let url_path = url.path().to_string(); - Ok((url_path, entry.full_path.clone())) -} diff --git a/src/models.rs b/src/models.rs index a3183e6..6035ce1 100644 --- a/src/models.rs +++ b/src/models.rs @@ -1,5 +1,6 @@ use relative_path::RelativePathBuf; use serde::Deserialize; +use url::Url; /// Generic Model for paginated API. #[derive(Debug, serde::Deserialize)] @@ -30,7 +31,7 @@ pub struct Chapter { #[derive(Debug, Deserialize)] pub struct FileEntry { pub ourn: String, - pub url: String, + pub url: Url, pub full_path: RelativePathBuf, pub media_type: String, pub filename: String, -- cgit v1.2.3-70-g09d2