use crate::{dom, error::FullTextParserError, util::Util};
use dom_query::NodeRef;
use url::Url;
pub struct VideoObject {
thumbnail_url: Option<String>,
content_url: Option<Url>,
embed_url: Option<Url>,
description: Option<String>,
name: Option<String>,
}
impl VideoObject {
pub fn parse_node(node: &NodeRef) -> Option<Self> {
if !dom::tag_name_is(node, "div") {
return None;
}
let item_prop_video = dom::attr(node, "itemprop")
.map(|prop| prop == "video")
.unwrap_or(false);
let item_type_video = Util::has_schema_org_type(node, "VideoObject");
if !item_prop_video && !item_type_video {
return None;
}
let meta_nodes = dom::elements_by_tag_name(node, "meta");
let mut thumbnail_url = None;
let mut content_url = None;
let mut embed_url = None;
let mut description = None;
let mut name = None;
for meta_node in meta_nodes {
let item_prop = dom::attr(&meta_node, "itemprop");
let content_prop = dom::attr(&meta_node, "content");
if let (Some(item_prop), Some(content_prop)) = (item_prop, content_prop) {
if item_prop == "thumbnailUrl" {
thumbnail_url = Some(content_prop);
} else if item_prop == "contentURL" {
content_url = Self::parse_url(&content_prop);
} else if item_prop == "embedURL" {
embed_url = Self::parse_url(&content_prop);
} else if item_prop == "description" {
description = Some(content_prop);
} else if item_prop == "name" {
name = Some(content_prop);
}
}
}
if thumbnail_url.is_none()
&& content_url.is_none()
&& embed_url.is_none()
&& description.is_none()
&& name.is_none()
{
return None;
}
Some(Self {
thumbnail_url,
content_url,
embed_url,
description,
name,
})
}
fn parse_url(url: &str) -> Option<Url> {
let url = if url.starts_with("//") {
format!("https:{url}")
} else {
url.into()
};
Url::parse(&url)
.inspect_err(|err| tracing::error!(%err, "parse video object url"))
.ok()
}
pub fn replace(&self, node: &NodeRef) -> Result<(), FullTextParserError> {
node.parent().ok_or(FullTextParserError::Dom)?;
let tree = node.tree;
let root = tree.new_element("videoobject");
dom::replace_with(node, &root);
if let Some(name) = self.name.as_deref() {
let title = tree.new_element("h3");
dom::append_child(&root, &title);
dom::append_child(&title, &tree.new_text(name));
}
if self.name != self.description
&& let Some(description) = self.description.as_deref()
{
let desc = tree.new_element("p");
dom::append_child(&root, &desc);
dom::append_child(&desc, &tree.new_text(description));
}
let a = tree.new_element("a");
dom::append_child(&root, &a);
if let Some(embed_url) = self.embed_url.as_ref() {
a.set_attr("href", embed_url.as_str());
} else if let Some(content_url) = self.content_url.as_ref() {
a.set_attr("href", content_url.as_str());
}
let img = tree.new_element("img");
dom::append_child(&a, &img);
if let Some(thumbnail_url) = self.thumbnail_url.as_deref() {
img.set_attr("src", thumbnail_url);
}
Ok(())
}
}