diff --git a/Cargo.toml b/Cargo.toml
index bcfdfbc..a8a7d68 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,11 +13,10 @@ include = ["/src", "README.md", "LICENSE", "!snapshots"]
members = [".", "codegen", "cli"]
[features]
-default = ["default-tls", "rss"]
-all = ["rss", "html"]
+default = ["default-tls"]
+all = ["rss"]
rss = ["quick-xml"]
-html = ["askama_escape"]
# Reqwest TLS
default-tls = ["reqwest/default-tls"]
@@ -45,7 +44,6 @@ filenamify = "0.1.0"
ress = "0.11.4"
phf = "0.11.1"
base64 = "0.13.0"
-askama_escape = {version = "0.10.3", optional = true}
quick-xml = {version = "0.25.0", features = ["serialize"], optional = true}
[dev-dependencies]
diff --git a/src/model/richtext.rs b/src/model/richtext.rs
index f8ef5f2..c4609be 100644
--- a/src/model/richtext.rs
+++ b/src/model/richtext.rs
@@ -2,6 +2,8 @@
use serde::{Deserialize, Serialize};
+use crate::util;
+
use super::UrlTarget;
#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
@@ -32,8 +34,6 @@ pub trait ToPlaintext {
}
/// Trait for converting rich text to html.
-#[cfg(feature = "html")]
-#[cfg_attr(docsrs, doc(cfg(feature = "html")))]
pub trait ToHtml {
/// Convert rich text to html.
fn to_html(&self) -> String {
@@ -72,26 +72,22 @@ impl ToPlaintext for TextComponent {
}
}
-#[cfg(feature = "html")]
-#[cfg_attr(docsrs, doc(cfg(feature = "html")))]
impl ToHtml for TextComponent {
fn to_html_yt_host(&self, yt_host: &str) -> String {
match self {
- TextComponent::Text(text) => askama_escape::escape(&text, askama_escape::Html)
- .to_string()
- .replace("\n", "
"),
+ TextComponent::Text(text) => util::escape_html(text),
TextComponent::Web { text, .. } => {
format!(
r#"{}"#,
self.get_url(yt_host),
- askama_escape::escape(text, askama_escape::Html)
+ util::escape_html(text)
)
}
_ => {
format!(
r#"{}"#,
self.get_url(yt_host),
- askama_escape::escape(self.get_text(), askama_escape::Html)
+ util::escape_html(self.get_text())
)
}
}
@@ -107,8 +103,6 @@ impl ToPlaintext for RichText {
}
}
-#[cfg(feature = "html")]
-#[cfg_attr(docsrs, doc(cfg(feature = "html")))]
impl ToHtml for RichText {
fn to_html_yt_host(&self, yt_host: &str) -> String {
self.0.iter().map(|c| c.to_html_yt_host(yt_host)).collect()
@@ -186,7 +180,6 @@ aespa 에스파 'Black Mamba' MV ℗ SM Entertainment"#
);
}
- #[cfg(feature = "html")]
#[test]
fn t_to_html() {
let richtext = RichText::from(TEXT_SOURCE.clone());
diff --git a/src/util/mod.rs b/src/util/mod.rs
index 02a746f..e59f19c 100644
--- a/src/util/mod.rs
+++ b/src/util/mod.rs
@@ -312,6 +312,24 @@ where
.ok()
}
+/// Replace all html control characters to make a string safe for inserting into HTML.
+pub fn escape_html(input: &str) -> String {
+ let mut buf = String::with_capacity(input.len());
+
+ for c in input.chars() {
+ match c {
+ '<' => buf.push_str("<"),
+ '>' => buf.push_str(">"),
+ '&' => buf.push_str("&"),
+ '"' => buf.push_str("""),
+ '\'' => buf.push_str("'"),
+ '\n' => buf.push_str("
"),
+ _ => buf.push(c),
+ };
+ }
+ buf
+}
+
#[cfg(test)]
mod tests {
use std::{fs::File, io::BufReader, path::Path};
diff --git a/tests/youtube.rs b/tests/youtube.rs
index 51064ec..8bfee49 100644
--- a/tests/youtube.rs
+++ b/tests/youtube.rs
@@ -1,7 +1,7 @@
use std::collections::HashSet;
use rstest::rstest;
-use time::macros::{date, datetime};
+use time::macros::date;
use time::OffsetDateTime;
use rustypipe::client::{ClientType, RustyPipe};
@@ -1138,6 +1138,7 @@ async fn channel_not_found(#[case] id: &str) {
#[cfg(feature = "rss")]
mod channel_rss {
use super::*;
+ use time::macros::datetime;
#[tokio::test]
async fn get_channel_rss() {