github infobox
This commit is contained in:
parent
f95c5fe273
commit
60914e6e7f
20
Cargo.lock
generated
20
Cargo.lock
generated
@ -39,6 +39,19 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ammonia"
|
||||||
|
version = "3.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "64e6d1c7838db705c9b756557ee27c384ce695a1c51a6fe528784cb1c6840170"
|
||||||
|
dependencies = [
|
||||||
|
"html5ever",
|
||||||
|
"maplit",
|
||||||
|
"once_cell",
|
||||||
|
"tendril",
|
||||||
|
"url",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.75"
|
version = "1.0.75"
|
||||||
@ -753,6 +766,12 @@ version = "0.1.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
|
checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "maplit"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "markup5ever"
|
name = "markup5ever"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
@ -792,6 +811,7 @@ checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
|
|||||||
name = "metasearch2"
|
name = "metasearch2"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"ammonia",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-stream",
|
"async-stream",
|
||||||
"axum",
|
"axum",
|
||||||
|
@ -6,6 +6,7 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
ammonia = "3.3.0"
|
||||||
anyhow = "1.0.75"
|
anyhow = "1.0.75"
|
||||||
async-stream = "0.3.5"
|
async-stream = "0.3.5"
|
||||||
axum = { version = "0.7.2", features = ["http2"] }
|
axum = { version = "0.7.2", features = ["http2"] }
|
||||||
|
@ -6,7 +6,6 @@ use serde::Deserialize;
|
|||||||
use crate::engines::{EngineResponse, CLIENT};
|
use crate::engines::{EngineResponse, CLIENT};
|
||||||
|
|
||||||
pub fn request(query: &str) -> reqwest::RequestBuilder {
|
pub fn request(query: &str) -> reqwest::RequestBuilder {
|
||||||
println!("request wikipedia");
|
|
||||||
CLIENT
|
CLIENT
|
||||||
.get(
|
.get(
|
||||||
Url::parse_with_params(
|
Url::parse_with_params(
|
||||||
|
@ -28,6 +28,7 @@ pub enum Engine {
|
|||||||
Wikipedia,
|
Wikipedia,
|
||||||
// post-search
|
// post-search
|
||||||
StackOverflow,
|
StackOverflow,
|
||||||
|
GitHub,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Engine {
|
impl Engine {
|
||||||
@ -41,6 +42,7 @@ impl Engine {
|
|||||||
Engine::Calc,
|
Engine::Calc,
|
||||||
Engine::Wikipedia,
|
Engine::Wikipedia,
|
||||||
Engine::StackOverflow,
|
Engine::StackOverflow,
|
||||||
|
Engine::GitHub,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,6 +56,7 @@ impl Engine {
|
|||||||
Engine::Calc => "calc",
|
Engine::Calc => "calc",
|
||||||
Engine::Wikipedia => "wikipedia",
|
Engine::Wikipedia => "wikipedia",
|
||||||
Engine::StackOverflow => "stackoverflow",
|
Engine::StackOverflow => "stackoverflow",
|
||||||
|
Engine::GitHub => "github",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,6 +110,7 @@ impl Engine {
|
|||||||
pub fn postsearch_request(&self, response: &Response) -> Option<reqwest::RequestBuilder> {
|
pub fn postsearch_request(&self, response: &Response) -> Option<reqwest::RequestBuilder> {
|
||||||
match self {
|
match self {
|
||||||
Engine::StackOverflow => postsearch::stackoverflow::request(response),
|
Engine::StackOverflow => postsearch::stackoverflow::request(response),
|
||||||
|
Engine::GitHub => postsearch::github::request(response),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -114,6 +118,7 @@ impl Engine {
|
|||||||
pub fn postsearch_parse_response(&self, body: &str) -> Option<String> {
|
pub fn postsearch_parse_response(&self, body: &str) -> Option<String> {
|
||||||
match self {
|
match self {
|
||||||
Engine::StackOverflow => postsearch::stackoverflow::parse_response(body),
|
Engine::StackOverflow => postsearch::stackoverflow::parse_response(body),
|
||||||
|
Engine::GitHub => postsearch::github::parse_response(body),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,4 +2,5 @@
|
|||||||
//! results. They can only show stuff in infoboxes and don't get requested if
|
//! results. They can only show stuff in infoboxes and don't get requested if
|
||||||
//! an infobox was added by another earlier engine.
|
//! an infobox was added by another earlier engine.
|
||||||
|
|
||||||
|
pub mod github;
|
||||||
pub mod stackoverflow;
|
pub mod stackoverflow;
|
||||||
|
56
src/engines/postsearch/github.rs
Normal file
56
src/engines/postsearch/github.rs
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
use reqwest::Url;
|
||||||
|
use scraper::{Html, Selector};
|
||||||
|
|
||||||
|
use crate::engines::{Response, CLIENT};
|
||||||
|
|
||||||
|
pub fn request(response: &Response) -> Option<reqwest::RequestBuilder> {
|
||||||
|
for search_result in response.search_results.iter().take(8) {
|
||||||
|
if search_result.url.starts_with("https://github.com/") {
|
||||||
|
return Some(CLIENT.get(search_result.url.as_str()).header(
|
||||||
|
"User-Agent",
|
||||||
|
"Mozilla/5.0 (X11; Linux x86_64; rv:121.0) Gecko/20100101 Firefox/121.0",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_response(body: &str) -> Option<String> {
|
||||||
|
let dom = Html::parse_document(body);
|
||||||
|
|
||||||
|
let url = Url::join(
|
||||||
|
&Url::parse("https://github.com").unwrap(),
|
||||||
|
dom.select(&Selector::parse("main #repository-container-header a").unwrap())
|
||||||
|
.next()?
|
||||||
|
.value()
|
||||||
|
.attr("href")?,
|
||||||
|
)
|
||||||
|
.ok()?
|
||||||
|
.to_string();
|
||||||
|
let readme = dom.select(&Selector::parse("article").unwrap()).next()?;
|
||||||
|
let readme_html = readme.inner_html().trim().to_string();
|
||||||
|
|
||||||
|
let mut readme_html = ammonia::Builder::default()
|
||||||
|
.link_rel(None)
|
||||||
|
.url_relative(ammonia::UrlRelative::RewriteWithBase(
|
||||||
|
Url::parse("https://github.com").unwrap(),
|
||||||
|
))
|
||||||
|
.clean(&readme_html)
|
||||||
|
.to_string();
|
||||||
|
|
||||||
|
let readme_dom = Html::parse_fragment(&readme_html);
|
||||||
|
let title_el = readme_dom.select(&Selector::parse("h1").unwrap()).next()?;
|
||||||
|
let title_html = title_el.html().trim().to_string();
|
||||||
|
if readme_html.starts_with(&title_html) {
|
||||||
|
readme_html = readme_html[title_html.len()..].to_string();
|
||||||
|
}
|
||||||
|
let title = title_el.text().collect::<String>();
|
||||||
|
|
||||||
|
Some(format!(
|
||||||
|
r#"<a href="{url}"><h1>{title}</h1></a>
|
||||||
|
<div class="infobox-github-readme">{readme_html}</div>"#,
|
||||||
|
url = html_escape::encode_quoted_attribute(&url),
|
||||||
|
title = html_escape::encode_text(&title),
|
||||||
|
))
|
||||||
|
}
|
@ -49,7 +49,7 @@ pub fn parse_response(body: &str) -> Option<String> {
|
|||||||
let url = format!("{url}#{answer_id}");
|
let url = format!("{url}#{answer_id}");
|
||||||
|
|
||||||
Some(format!(
|
Some(format!(
|
||||||
r#"<a href="{url}" class="title"><h2>{title}</h2></a>
|
r#"<a href="{url}"><h2>{title}</h2></a>
|
||||||
<div class="infobox-stackoverflow-answer">{answer_html}</div>"#,
|
<div class="infobox-stackoverflow-answer">{answer_html}</div>"#,
|
||||||
url = html_escape::encode_quoted_attribute(&url.to_string()),
|
url = html_escape::encode_quoted_attribute(&url.to_string()),
|
||||||
title = html_escape::encode_text(&title),
|
title = html_escape::encode_text(&title),
|
||||||
|
@ -22,3 +22,11 @@ searchInputEl.addEventListener("input", async (e) => {
|
|||||||
datalistEl.appendChild(optionEl);
|
datalistEl.appendChild(optionEl);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// if the user starts typing but they don't have focus on the input, focus it
|
||||||
|
document.addEventListener("keydown", (e) => {
|
||||||
|
// must be a letter or number
|
||||||
|
if (e.key.match(/^[a-z0-9]$/i) && !searchInputEl.matches(":focus")) {
|
||||||
|
searchInputEl.focus();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
@ -11,7 +11,7 @@ use bytes::Bytes;
|
|||||||
use html_escape::{encode_text, encode_unquoted_attribute};
|
use html_escape::{encode_text, encode_unquoted_attribute};
|
||||||
|
|
||||||
use crate::engines::{
|
use crate::engines::{
|
||||||
self, Engine, EngineProgressUpdate, ProgressUpdate, ProgressUpdateData, Response, SearchQuery,
|
self, Engine, EngineProgressUpdate, ProgressUpdateData, Response, SearchQuery,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn render_beginning_of_html(query: &str) -> String {
|
fn render_beginning_of_html(query: &str) -> String {
|
||||||
|
Loading…
Reference in New Issue
Block a user