diff --git a/Cargo.lock b/Cargo.lock index 60297ca..41642aa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -636,6 +636,8 @@ dependencies = [ "color-art", "comrak", "itertools", + "mime_guess", + "mime_serde_shim", "serde", "serde_json", "serde_with", @@ -649,6 +651,32 @@ version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "mime_serde_shim" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab9c5b33b135e34aab675cef7f678c688b30740ba299d75e3a8c0af89b5d5cea" +dependencies = [ + "mime", + "serde", +] + [[package]] name = "miniz_oxide" version = "0.7.2" @@ -1094,6 +1122,15 @@ version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-bidi" version = "0.3.15" @@ -1145,6 +1182,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + [[package]] name = "walkdir" version = "2.5.0" diff --git a/Cargo.toml b/Cargo.toml index 46c6503..3528673 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,8 @@ clio = { version = "0.3.5", features = ["clap-parse"] } color-art = "0.3.8" comrak = "0.21.0" itertools = "0.12.1" +mime_guess = "2.0.4" +mime_serde_shim = "0.2.2" serde = { version = "1.0.197", features = ["derive"] } serde_json = "1.0.114" serde_with = { version = "3.7.0", features = [ "macros" ] } diff --git a/src/convert/npf.rs b/src/convert/npf.rs index c2d7ab0..b0bc34f 100644 --- a/src/convert/npf.rs +++ b/src/convert/npf.rs @@ -1,4 +1,4 @@ -use std::cell::RefCell; +use std::{borrow::Borrow, cell::RefCell, path, str::FromStr}; use comrak::{ arena_tree::{Children, Node}, @@ -13,12 +13,11 @@ pub mod text_formatting; mod objects_post; -use content_blocks::{BlockText, BlockValue}; +use content_blocks::{BlockImage, BlockText, BlockValue}; +use objects::{BlogInfo, Media}; use text_formatting::{FormatTypeBold, FormatTypeItalic, FormatValue}; -use text_formatting::{FormatTypeLink, FormatTypeStrikeThrough}; - -use self::{objects::BlogInfo, text_formatting::FormatTypeMention}; +use text_formatting::{FormatTypeLink, FormatTypeMention, FormatTypeStrikeThrough}; #[derive(Debug)] pub enum NPFConvertError { @@ -164,6 +163,53 @@ impl<'a> TryFrom<&'a Node<'a, RefCell>> for objects::Post { post.content.push(BlockValue::Text(BlockText::from("\n"))); Ok(post) } + NodeValue::Image(i) => { + let alt_text = Self::try_from(node.children())?.fold_content(); + if let Some(p) = node.parent() { + if let NodeValue::Paragraph = p.data.borrow().value { + let alt_text = alt_text + .content + .iter() + .find(|b| { + if let BlockValue::Text(_) = b { + true + } else { + false + } + }) + .unwrap_or(BlockValue::Text(BlockText::new("")).borrow()) + .to_owned(); + let alt_text = if let BlockValue::Text(t) = alt_text { + Some(t.text.clone()) + } else { + None + }; + + let media = if let Ok(url) = url::Url::from_str(&i.url) { + Media::from(url) + } else if let Some(name) = path::Path::new(&i.url).file_name() { + if let Some(name) = name.to_str() { + Media::from(name) + } else { + Media::from(i.url.as_str()) + } + } else { + Media::from(i.url.as_str()) + }; + + let mut block = BlockImage::from(media); + block.alt_text = alt_text; + + let mut post = Self::new(0); + post.content.push(BlockValue::Image(block)); + Ok(post) + } else { + Ok(alt_text) + } + } else { + Ok(alt_text) + } + } _ => Ok(Self::new(0)), } } @@ -411,7 +457,7 @@ mod tests { let markdown = "If **you** are reading this, thanks for giving a look\n\ and checking the ~~ugly~~ source code of this *little\n\ **personal** project*. It is heart warming to know that *at least*\n\ - [someone](t:_YENQUPzd_oPpmVDqZQ-yw) found this interesting and maybe useful, even knowing\n\ + [someone](t:_YENQUPzd_oPpmVDqZQ-yw) found this interesting and maybe useful, ![even knowing](image.png)\n\ how niched this whole project is.\\ - [Gustavo \"Guz\" L. de Mello](https://guz.one), Apr 16, 12.2024"; diff --git a/src/convert/npf/objects.rs b/src/convert/npf/objects.rs index f2527f0..93abfc8 100644 --- a/src/convert/npf/objects.rs +++ b/src/convert/npf/objects.rs @@ -1,6 +1,7 @@ use serde::{Deserialize, Serialize}; pub use super::objects_post::Post; +use mime_serde_shim::Wrapper as Mime; #[serde_with::skip_serializing_none] #[derive(Debug, Deserialize, Serialize, Clone)] @@ -78,8 +79,9 @@ pub struct Avatar { #[serde_with::skip_serializing_none] #[derive(Debug, Deserialize, Serialize, Clone)] pub struct Media { - pub r#type: Option, - pub url: url::Url, + pub r#type: Option, + pub url: Option, + pub identifier: Option, pub width: Option, pub height: Option, pub original_dimensions_missing: Option, @@ -87,13 +89,17 @@ pub struct Media { pub has_original_dimentions: Option, } impl Media { - pub fn new(url: url::Url) -> Self { - Self::from(url) + pub fn new(identifier: String) -> Self { + Self::from(identifier) + } + pub fn is_valid(&self) -> bool { + self.url.is_some() || self.identifier.is_some() } fn default() -> Self { Self { r#type: None, - url: url::Url::parse("https://tumblr.com").unwrap(), + url: None, + identifier: None, width: None, height: None, original_dimensions_missing: None, @@ -102,10 +108,35 @@ impl Media { } } } +impl From for Media { + fn from(value: String) -> Self { + let mime = if let Some(m) = mime_guess::from_path(&value).first() { + Some(Mime::from(m)) + } else { + None + }; + Self { + r#type: mime, + identifier: Some(value), + ..Self::default() + } + } +} +impl From<&str> for Media { + fn from(value: &str) -> Self { + Self::from(String::from(value)) + } +} impl From for Media { fn from(value: url::Url) -> Self { + let mime = if let Some(m) = mime_guess::from_path(&value.to_string()).first() { + Some(Mime::from(m)) + } else { + None + }; Self { - url: value, + r#type: mime, + url: Some(value), ..Self::default() } }