diff --git a/Cargo.lock b/Cargo.lock index d9a249e..5eac185 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -53,7 +53,7 @@ dependencies = [ "actix-service", "actix-utils", "ahash 0.8.3", - "base64", + "base64 0.21.4", "bitflags 2.4.1", "brotli", "bytes", @@ -422,6 +422,12 @@ version = "0.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" +[[package]] +name = "base64" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" + [[package]] name = "base64-simd" version = "0.7.0" @@ -1146,12 +1152,14 @@ version = "0.1.0" dependencies = [ "actix-files", "actix-web", + "base64 0.22.0", "cached", "chrono", "chrono-tz", "comrak", "glob", "lol_html", + "mime_guess", "minify-html", "minify-js 0.6.0", "ramhorns", @@ -2387,7 +2395,7 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a4a0cfc5fb21a09dc6af4bf834cf10d4a32fccd9e2ea468c4b1751a097487aa" dependencies = [ - "base64", + "base64 0.21.4", "indexmap 1.9.3", "line-wrap", "quick-xml", @@ -2712,7 +2720,7 @@ version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d66674f2b6fb864665eea7a3c1ac4e3dfacd2fda83cf6f935a612e01b0e3338" dependencies = [ - "base64", + "base64 0.21.4", "bytes", "encoding_rs", "futures-core", @@ -2853,7 +2861,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "base64", + "base64 0.21.4", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index f7bf517..f54d29d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,3 +27,5 @@ chrono = { version = "0.4", default-features = false, features = ["clock"]} chrono-tz = "0.8" rss = { version = "2.0", features = ["atom"] } lol_html = "1.2" +base64 = "0.22.0" +mime_guess = "2.0.4" diff --git a/src/misc/markdown.rs b/src/misc/markdown.rs index 7e3228a..3826ae1 100644 --- a/src/misc/markdown.rs +++ b/src/misc/markdown.rs @@ -1,10 +1,13 @@ use crate::misc::date::Date; +use base64::engine::general_purpose; +use base64::Engine; use comrak::nodes::{AstNode, NodeValue}; use comrak::{format_html, parse_document, Arena, ComrakOptions, ListStyleType}; use lol_html::{element, rewrite_str, HtmlRewriter, RewriteStrSettings, Settings}; use ramhorns::Content; use serde::{Deserialize, Deserializer}; use std::fs; +use std::path::Path; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; @@ -192,8 +195,35 @@ fn custom_img_size(html: String) -> String { .unwrap() } +/// Fix local images +fn fix_local_img(path: &str, html: String) -> String { + rewrite_str( + &html, + RewriteStrSettings { + element_content_handlers: vec![element!("img", |el| { + if let Some(src) = el.get_attribute("src") { + if let Some(img_src) = Path::new(path).parent() { + let img_path = img_src.join(src); + let file = fs::read_to_string(&img_path).unwrap(); + let encoded = general_purpose::STANDARD.encode(file); + let mime_type = mime_guess::from_path(img_path) + .first_or_octet_stream() + .to_string(); + el.set_attribute("src", &format!("data:{};base64,{}", mime_type, encoded)) + .unwrap(); + } + } + + Ok(()) + })], + ..RewriteStrSettings::default() + }, + ) + .unwrap() +} + /// Transform markdown string to File structure -fn read(raw_text: &str, metadata_type: TypeFileMetadata) -> File { +fn read(path: &str, raw_text: &str, metadata_type: TypeFileMetadata) -> File { let arena = Arena::new(); let options = get_options(); @@ -212,6 +242,7 @@ fn read(raw_text: &str, metadata_type: TypeFileMetadata) -> File { let mut html_content = String::from_utf8(html).unwrap(); html_content = custom_img_size(html_content); + html_content = fix_local_img(path, html_content); File { metadata: Metadata { @@ -227,7 +258,7 @@ fn read(raw_text: &str, metadata_type: TypeFileMetadata) -> File { /// Read markdown file pub fn read_file(filename: &str, expected_file: TypeFileMetadata) -> Option { match fs::read_to_string(filename) { - Ok(text) => Some(read(&text, expected_file)), + Ok(text) => Some(read(filename, &text, expected_file)), _ => None, } }