diff --git a/article_scraper/resources/tests/ftr/hardwareluxx/expected.html b/article_scraper/resources/tests/ftr/hardwareluxx/expected.html index 625cffb..7fe36f6 100644 --- a/article_scraper/resources/tests/ftr/hardwareluxx/expected.html +++ b/article_scraper/resources/tests/ftr/hardwareluxx/expected.html @@ -19,6 +19,6 @@ Mod gibt dem 25 Jahr alten Shooter neuen Glanz

Mod gibt dem 25 Jahr alten Shooter neuen Glanz
-

25 Jahre ist es nun her, dass Physiker Gordon Freeman und seine Brechstange zu den Helden eines bis heute legendären Ego-Shooters wurden. Mit Half-Life hat Valve eines der erfolgreichsten Spiele aller Zeiten produziert. Kein Wunder also, dass es bis heute eine aktive Fan-Base rund um den Titel gibt. 

Während immer wieder Gerüchte um einen eventuellen dritten Teil der Reihe aufflammen, haben Modder im Laufe der Jahre unzählige Mods und Total Conversions für das Ur-Spiel produziert. Unter dem Nickname sultim_t hat nun einer von ihnen Raytracing in Half-Life 1 integriert. Die Bilder zeigen eindrucksvoll, wie stark sich die neue Technik selbst in einem so alten Spiel auf das Erlebnis auswirkt. Neben Lampen und Displays haben auch die Waffen des Protagonisten neue Licht- und Schatteneffekte erhalten.

Wer die Mod selbst ausprobieren möchte, benötigt die Originalversion von Half-Life. Nach der Installation über Steam muss im Zielordner erst die Zip-Datei der Mod entpackt werden. Danach die Datei xash3d.exe starten und mit der X-Taste die neuen Render aktivieren. Half Life von 1998 gibt es auf Steam aktuell für 8,19 Euro. Die Mod gibt es kostenlos auf der GitHub-Seite von sultim_t. Dort findet sich auch eine genaue Anleitung zur Installation. 

Datenschutzhinweis für Youtube



An dieser Stelle möchten wir Ihnen ein Youtube-Video zeigen. Ihre Daten zu schützen, liegt uns aber am Herzen: Youtube setzt durch das Einbinden und Abspielen Cookies auf ihrem Rechner, mit welchen Sie eventuell getracked werden können. Wenn Sie dies zulassen möchten, klicken Sie einfach auf den Play-Button. Das Video wird anschließend geladen und danach abgespielt.

Ihr Hardwareluxx-Team

Youtube Videos ab jetzt direkt anzeigen

+

25 Jahre ist es nun her, dass Physiker Gordon Freeman und seine Brechstange zu den Helden eines bis heute legendären Ego-Shooters wurden. Mit Half-Life hat Valve eines der erfolgreichsten Spiele aller Zeiten produziert. Kein Wunder also, dass es bis heute eine aktive Fan-Base rund um den Titel gibt. 

Während immer wieder Gerüchte um einen eventuellen dritten Teil der Reihe aufflammen, haben Modder im Laufe der Jahre unzählige Mods und Total Conversions für das Ur-Spiel produziert. Unter dem Nickname sultim_t hat nun einer von ihnen Raytracing in Half-Life 1 integriert. Die Bilder zeigen eindrucksvoll, wie stark sich die neue Technik selbst in einem so alten Spiel auf das Erlebnis auswirkt. Neben Lampen und Displays haben auch die Waffen des Protagonisten neue Licht- und Schatteneffekte erhalten.

Wer die Mod selbst ausprobieren möchte, benötigt die Originalversion von Half-Life. Nach der Installation über Steam muss im Zielordner erst die Zip-Datei der Mod entpackt werden. Danach die Datei xash3d.exe starten und mit der X-Taste die neuen Render aktivieren. Half Life von 1998 gibt es auf Steam aktuell für 8,19 Euro. Die Mod gibt es kostenlos auf der GitHub-Seite von sultim_t. Dort findet sich auch eine genaue Anleitung zur Installation. 

\ No newline at end of file diff --git a/article_scraper/src/full_text_parser/mod.rs b/article_scraper/src/full_text_parser/mod.rs index afd6bc8..4047bd3 100644 --- a/article_scraper/src/full_text_parser/mod.rs +++ b/article_scraper/src/full_text_parser/mod.rs @@ -1115,6 +1115,7 @@ impl FullTextParser { pub(crate) fn post_process_page(node: &mut Node) -> Result<(), FullTextParserError> { Util::clean_headers(node); + Util::replace_schema_org_orbjects(node); Util::clean_conditionally(node, "fieldset"); Util::clean_conditionally(node, "table"); Util::clean_conditionally(node, "ul"); diff --git a/article_scraper/src/lib.rs b/article_scraper/src/lib.rs index 1acdf87..05ca541 100644 --- a/article_scraper/src/lib.rs +++ b/article_scraper/src/lib.rs @@ -42,6 +42,7 @@ mod full_text_parser; #[doc(hidden)] pub mod images; mod util; +mod video_object; use crate::images::Progress; use article::Article; diff --git a/article_scraper/src/util.rs b/article_scraper/src/util.rs index abf06f4..c5db18a 100644 --- a/article_scraper/src/util.rs +++ b/article_scraper/src/util.rs @@ -13,6 +13,7 @@ use tokio::fs::DirEntry; use crate::{ constants, full_text_parser::{config::ConfigEntry, error::FullTextParserError}, + video_object::VideoObject, }; pub struct Util; @@ -570,6 +571,16 @@ impl Util { } } + pub fn replace_schema_org_orbjects(root: &mut Node) { + let nodes = Util::get_elements_by_tag_name(root, "div"); + + for mut node in nodes.into_iter().rev() { + if let Some(video_object) = VideoObject::parse_node(&node) { + _ = video_object.replace(&mut node); + } + } + } + // Clean an element of all tags of type "tag" if they look fishy. // "Fishy" is an algorithm based on content length, classnames, link density, number of images & embeds, etc. pub fn clean_conditionally(root: &mut Node, tag: &str) { diff --git a/article_scraper/src/video_object.rs b/article_scraper/src/video_object.rs new file mode 100644 index 0000000..b3bd1c2 --- /dev/null +++ b/article_scraper/src/video_object.rs @@ -0,0 +1,111 @@ +use crate::{full_text_parser::error::FullTextParserError, util::Util}; +use libxml::tree::Node; +use url::Url; + +pub struct VideoObject { + thumbnail_url: Option, + content_url: Option, + embed_url: Option, + description: Option, + name: Option, +} + +impl VideoObject { + pub fn parse_node(node: &Node) -> Option { + if node.get_name().to_uppercase() != "DIV" { + return None; + } + + let item_prop_video = node + .get_attribute("itemprop") + .map(|prop| prop == "video") + .unwrap_or(false); + let item_type_video = node + .get_attribute("itemtype") + .map(|attr| attr == "http://schema.org/VideoObject") + .unwrap_or(false); + + if !item_prop_video && !item_type_video { + return None; + } + + let meta_nodes = Util::get_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 = meta_node.get_attribute("itemprop"); + let content_prop = meta_node.get_attribute("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 { + let url = if url.starts_with("//") { + format!("https:{url}") + } else { + url.into() + }; + + Url::parse(&url) + .map_err(|err| log::error!("parse video object url: {err}")) + .ok() + } + + pub fn replace(&self, node: &mut Node) -> Result<(), FullTextParserError> { + let mut parent = node.get_parent().ok_or(FullTextParserError::Xml)?; + node.unlink(); + + let mut a = parent + .new_child(None, "a") + .map_err(|_| FullTextParserError::Xml)?; + if let Some(embed_url) = self.embed_url.as_ref() { + _ = a.set_attribute("href", embed_url.as_str()); + } else if let Some(content_url) = self.content_url.as_ref() { + _ = a.set_attribute("href", content_url.as_str()); + } + + let mut img = a + .new_child(None, "img") + .map_err(|_| FullTextParserError::Xml)?; + if let Some(thumbnail_url) = self.thumbnail_url.as_deref() { + _ = img.set_attribute("src", thumbnail_url); + } + + Ok(()) + } +}