mirror of
https://github.com/Myzel394/tifsep.git
synced 2025-06-18 15:35:26 +02:00
feat: Add favicon support; improvements & bugfixes
This commit is contained in:
parent
877ecd1fee
commit
6269636e5a
154
Cargo.lock
generated
154
Cargo.lock
generated
@ -17,6 +17,19 @@ version = "1.0.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ahash"
|
||||||
|
version = "0.8.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d713b3834d76b85304d4d525563c1276e2e30dc97cc67bfb4585a4a29fc2c89f"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"getrandom",
|
||||||
|
"once_cell",
|
||||||
|
"version_check",
|
||||||
|
"zerocopy",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "1.1.2"
|
version = "1.1.2"
|
||||||
@ -26,6 +39,21 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "android-tzdata"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "android_system_properties"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-stream"
|
name = "async-stream"
|
||||||
version = "0.3.5"
|
version = "0.3.5"
|
||||||
@ -210,6 +238,20 @@ version = "1.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chrono"
|
||||||
|
version = "0.4.34"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b"
|
||||||
|
dependencies = [
|
||||||
|
"android-tzdata",
|
||||||
|
"iana-time-zone",
|
||||||
|
"js-sys",
|
||||||
|
"num-traits",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"windows-targets 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clang-sys"
|
name = "clang-sys"
|
||||||
version = "1.7.0"
|
version = "1.7.0"
|
||||||
@ -637,6 +679,29 @@ dependencies = [
|
|||||||
"tokio-native-tls",
|
"tokio-native-tls",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iana-time-zone"
|
||||||
|
version = "0.1.60"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141"
|
||||||
|
dependencies = [
|
||||||
|
"android_system_properties",
|
||||||
|
"core-foundation-sys",
|
||||||
|
"iana-time-zone-haiku",
|
||||||
|
"js-sys",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"windows-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iana-time-zone-haiku"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
@ -905,6 +970,15 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num_cpus"
|
name = "num_cpus"
|
||||||
version = "1.16.0"
|
version = "1.16.0"
|
||||||
@ -1038,6 +1112,48 @@ version = "2.3.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf"
|
||||||
|
version = "0.11.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
|
||||||
|
dependencies = [
|
||||||
|
"phf_macros",
|
||||||
|
"phf_shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf_generator"
|
||||||
|
version = "0.11.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0"
|
||||||
|
dependencies = [
|
||||||
|
"phf_shared",
|
||||||
|
"rand",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf_macros"
|
||||||
|
version = "0.11.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b"
|
||||||
|
dependencies = [
|
||||||
|
"phf_generator",
|
||||||
|
"phf_shared",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf_shared"
|
||||||
|
version = "0.11.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
|
||||||
|
dependencies = [
|
||||||
|
"siphasher",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project-lite"
|
name = "pin-project-lite"
|
||||||
version = "0.2.13"
|
version = "0.2.13"
|
||||||
@ -1546,6 +1662,12 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "siphasher"
|
||||||
|
version = "0.3.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
version = "0.4.9"
|
version = "0.4.9"
|
||||||
@ -1637,14 +1759,17 @@ dependencies = [
|
|||||||
name = "tcp_test"
|
name = "tcp_test"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"ahash",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
"chrono",
|
||||||
"futures",
|
"futures",
|
||||||
"html-escape",
|
"html-escape",
|
||||||
"lazy-regex",
|
"lazy-regex",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log",
|
"log",
|
||||||
"mio",
|
"mio",
|
||||||
|
"phf",
|
||||||
"regex",
|
"regex",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"rocket",
|
"rocket",
|
||||||
@ -2144,6 +2269,15 @@ dependencies = [
|
|||||||
"windows-targets 0.48.5",
|
"windows-targets 0.48.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-core"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.48.0"
|
version = "0.48.0"
|
||||||
@ -2304,6 +2438,26 @@ dependencies = [
|
|||||||
"is-terminal",
|
"is-terminal",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy"
|
||||||
|
version = "0.7.32"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
|
||||||
|
dependencies = [
|
||||||
|
"zerocopy-derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy-derive"
|
||||||
|
version = "0.7.32"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zeroize"
|
name = "zeroize"
|
||||||
version = "1.7.0"
|
version = "1.7.0"
|
||||||
|
@ -6,14 +6,17 @@ 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]
|
||||||
|
ahash = "0.8.9"
|
||||||
async-trait = "0.1.77"
|
async-trait = "0.1.77"
|
||||||
bytes = "1.5.0"
|
bytes = "1.5.0"
|
||||||
|
chrono = "0.4.34"
|
||||||
futures = "0.3.30"
|
futures = "0.3.30"
|
||||||
html-escape = "0.2.13"
|
html-escape = "0.2.13"
|
||||||
lazy-regex = "3.1.0"
|
lazy-regex = "3.1.0"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
log = "0.4.20"
|
log = "0.4.20"
|
||||||
mio = { version = "0.8.10", features = ["net", "os-poll", ] }
|
mio = { version = "0.8.10", features = ["net", "os-poll", ] }
|
||||||
|
phf = { version = "0.11.2", features = ["macros"] }
|
||||||
regex = "1.10.3"
|
regex = "1.10.3"
|
||||||
reqwest = { version = "0.11.23", features = ["stream"] }
|
reqwest = { version = "0.11.23", features = ["stream"] }
|
||||||
rocket = "0.5.0"
|
rocket = "0.5.0"
|
||||||
|
@ -14,9 +14,11 @@ pub mod bing {
|
|||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref RESULTS_START: Regex = Regex::new(r#"id="b_results""#).unwrap();
|
static ref RESULTS_START: Regex = Regex::new(r#"id="b_results""#).unwrap();
|
||||||
static ref SINGLE_RESULT: Regex = Regex::new(r#"<li class="b_algo".*?<h2.*?><a href="(?P<url>.+?)".*?>(?P<title>.+?)</a></h2>.*?((<div class="b_caption.*?<p.*?)|(<p class="b_lineclamp.*?))><span.*?</span>(?P<description>.*?)</p>.*?</li>"#).unwrap();
|
static ref SINGLE_RESULT: Regex = Regex::new(r#"<li class="b_algo".*?siteicon.*?>.*?<img src="(?P<image>.+?)"(?:.*?class="b_attribution".*?u="(?P<cache>.+?)")?.*?<h2.*?><a href="(?P<url>.+?)".*?>(?P<title>.+?)</a></h2>.*?((<div class="b_caption.*?<p.*?)|(<p class="b_lineclamp.*?))><span.*?</span>(?P<description>.*?)</p>.*?</li>"#).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DATE_FORMAT: &str = "%b %d, %Y";
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Bing {
|
pub struct Bing {
|
||||||
positions: EnginePositions,
|
positions: EnginePositions,
|
||||||
@ -24,8 +26,11 @@ pub mod bing {
|
|||||||
|
|
||||||
impl EngineBase for Bing {
|
impl EngineBase for Bing {
|
||||||
fn parse_next<'a>(&mut self) -> Option<SearchResult> {
|
fn parse_next<'a>(&mut self) -> Option<SearchResult> {
|
||||||
self.positions
|
self.positions.handle_block_using_default_method(
|
||||||
.handle_block_using_default_method(&SINGLE_RESULT, SearchEngine::Bing)
|
&SINGLE_RESULT,
|
||||||
|
SearchEngine::Bing,
|
||||||
|
Some(DATE_FORMAT),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_packet<'a>(&mut self, packet: impl Iterator<Item = &'a u8>) {
|
fn push_packet<'a>(&mut self, packet: impl Iterator<Item = &'a u8>) {
|
||||||
|
@ -14,9 +14,11 @@ pub mod brave {
|
|||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref RESULTS_START: Regex = Regex::new(r#"<body"#).unwrap();
|
static ref RESULTS_START: Regex = Regex::new(r#"<body"#).unwrap();
|
||||||
static ref SINGLE_RESULT: Regex = Regex::new(r#"<div class="snippet svelte-.+?<a href=.(?P<url>.+?)".+?<div class="title svelte-.+?">(?P<title>.+?)</div></div>.+?<div class="snippet-description.+?">(?P<description>.+?)</div></div>"#).unwrap();
|
static ref SINGLE_RESULT: Regex = Regex::new(r#"<div class="snippet svelte-.+?<a href=.(?P<url>.+?)".+?(?:.+?<img.+?src="(?P<image>.+?)")?.+?<div class="title svelte-.+?">(?P<title>.+?)</div></div>.+?<div class="snippet-description.+?">(?:(?P<date>.+?) - )?(?P<description>.+?)</div>.*?</div>.*?</div>"#).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DATE_FORMAT: &str = "%m %d, %Y";
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Brave {
|
pub struct Brave {
|
||||||
positions: EnginePositions,
|
positions: EnginePositions,
|
||||||
@ -24,8 +26,11 @@ pub mod brave {
|
|||||||
|
|
||||||
impl EngineBase for Brave {
|
impl EngineBase for Brave {
|
||||||
fn parse_next<'a>(&mut self) -> Option<SearchResult> {
|
fn parse_next<'a>(&mut self) -> Option<SearchResult> {
|
||||||
self.positions
|
self.positions.handle_block_using_default_method(
|
||||||
.handle_block_using_default_method(&SINGLE_RESULT, SearchEngine::Brave)
|
&SINGLE_RESULT,
|
||||||
|
SearchEngine::Brave,
|
||||||
|
Some(DATE_FORMAT),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_packet<'a>(&mut self, packet: impl Iterator<Item = &'a u8>) {
|
fn push_packet<'a>(&mut self, packet: impl Iterator<Item = &'a u8>) {
|
||||||
|
@ -25,8 +25,11 @@ pub mod duckduckgo {
|
|||||||
|
|
||||||
impl EngineBase for DuckDuckGo {
|
impl EngineBase for DuckDuckGo {
|
||||||
fn parse_next<'a>(&mut self) -> Option<SearchResult> {
|
fn parse_next<'a>(&mut self) -> Option<SearchResult> {
|
||||||
self.positions
|
self.positions.handle_block_using_default_method(
|
||||||
.handle_block_using_default_method(&SINGLE_RESULT, SearchEngine::DuckDuckGo)
|
&SINGLE_RESULT,
|
||||||
|
SearchEngine::DuckDuckGo,
|
||||||
|
None,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_packet<'a>(&mut self, packet: impl Iterator<Item = &'a u8>) {
|
fn push_packet<'a>(&mut self, packet: impl Iterator<Item = &'a u8>) {
|
||||||
|
@ -1,9 +1,16 @@
|
|||||||
pub mod engine_base {
|
pub mod engine_base {
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use std::{fmt::Debug, fmt::Display, sync::Arc};
|
use std::{
|
||||||
|
fmt::{Debug, Display},
|
||||||
|
hash::Hash,
|
||||||
|
ops::Sub,
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
|
use chrono::{DateTime, TimeDelta, TimeZone, Utc};
|
||||||
use futures::{lock::Mutex, Future, StreamExt};
|
use futures::{lock::Mutex, Future, StreamExt};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
use phf::phf_map;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use reqwest::{Error, Response};
|
use reqwest::{Error, Response};
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
@ -16,6 +23,9 @@ pub mod engine_base {
|
|||||||
static ref STRIP: Regex = Regex::new(r"[\s\n]+").unwrap();
|
static ref STRIP: Regex = Regex::new(r"[\s\n]+").unwrap();
|
||||||
static ref STRIP_HTML_TAGS: Regex =
|
static ref STRIP_HTML_TAGS: Regex =
|
||||||
Regex::new(r#"<(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+>"#).unwrap();
|
Regex::new(r#"<(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+>"#).unwrap();
|
||||||
|
static ref RELATIVE_DATETIME_PARSER: Regex =
|
||||||
|
Regex::new(r#"(?P<amount>\d+) (?P<unit>second|minute|hour|day|week|month|year)s? ago"#)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
@ -35,21 +45,34 @@ pub mod engine_base {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub struct SearchResultDate {
|
||||||
|
pub date: DateTime<Utc>,
|
||||||
|
// true if original date wasn't available and only
|
||||||
|
// a relative time such as "2 hours ago" was provided
|
||||||
|
pub is_relative: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct SearchResult {
|
pub struct SearchResult {
|
||||||
pub title: String,
|
pub title: String,
|
||||||
pub url: String,
|
pub url: String,
|
||||||
pub description: String,
|
pub description: String,
|
||||||
pub engine: SearchEngine,
|
pub engine: SearchEngine,
|
||||||
|
pub image_url: Option<String>,
|
||||||
|
pub date: Option<SearchResultDate>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hash for SearchResult {
|
||||||
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
|
self.url.hash(state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SearchResult {
|
impl SearchResult {
|
||||||
pub fn get_html_id(&self) -> String {
|
pub fn get_html_id(&self) -> String {
|
||||||
format!(
|
// IDs must start with a letter, so we add an "h" (html ID) to the beginning
|
||||||
"html-id-{}-{}",
|
format!("h{:X}", hash_string(&self.url),)
|
||||||
hash_string(&self.url),
|
|
||||||
self.url[self.url.len() - 5..].to_string(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,12 +100,26 @@ pub mod engine_base {
|
|||||||
let url = req.url().clone();
|
let url = req.url().clone();
|
||||||
let mut stream = req.bytes_stream();
|
let mut stream = req.bytes_stream();
|
||||||
|
|
||||||
|
let mut debug_has_fetched_once = false;
|
||||||
|
let mut debug_content = Vec::new();
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
println!("Requesting: {}", url);
|
||||||
|
}
|
||||||
|
|
||||||
while let Some(chunk) = stream.next().await {
|
while let Some(chunk) = stream.next().await {
|
||||||
let buffer = chunk.unwrap();
|
let buffer = chunk.unwrap();
|
||||||
|
|
||||||
self.push_packet(buffer.iter());
|
self.push_packet(buffer.iter());
|
||||||
|
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
debug_content.extend(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
while let Some(result) = self.parse_next() {
|
while let Some(result) = self.parse_next() {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
debug_has_fetched_once = true;
|
||||||
|
}
|
||||||
|
|
||||||
if tx.send(result).await.is_err() {
|
if tx.send(result).await.is_err() {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
@ -90,11 +127,25 @@ pub mod engine_base {
|
|||||||
}
|
}
|
||||||
|
|
||||||
while let Some(result) = self.parse_next() {
|
while let Some(result) = self.parse_next() {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
debug_has_fetched_once = true;
|
||||||
|
}
|
||||||
|
|
||||||
if tx.send(result).await.is_err() {
|
if tx.send(result).await.is_err() {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
if debug_has_fetched_once {
|
||||||
|
println!("Finished fetching: {}", url);
|
||||||
|
} else {
|
||||||
|
println!("{}", "==============");
|
||||||
|
println!("No results for: {}", url);
|
||||||
|
println!("{}", String::from_utf8_lossy(&debug_content));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -105,6 +156,16 @@ pub mod engine_base {
|
|||||||
pub started: bool,
|
pub started: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static UNIT_VALUES_MAP: phf::Map<&'static str, u32> = phf_map! {
|
||||||
|
"second" => 1,
|
||||||
|
"minute" => 60,
|
||||||
|
"hour" => 60 * 60,
|
||||||
|
"day" => 60 * 60 * 24,
|
||||||
|
"week" => 60 * 60 * 24 * 7,
|
||||||
|
"month" => 60 * 60 * 30,
|
||||||
|
"year" => 60 * 60 * 365,
|
||||||
|
};
|
||||||
|
|
||||||
impl EnginePositions {
|
impl EnginePositions {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
EnginePositions {
|
EnginePositions {
|
||||||
@ -113,6 +174,25 @@ pub mod engine_base {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parse_date(date: &str) -> Option<DateTime<Utc>> {
|
||||||
|
let raw_date_stripped = date.split_whitespace().collect::<Vec<&str>>().join(" ");
|
||||||
|
|
||||||
|
if let Some(capture) = RELATIVE_DATETIME_PARSER.captures(&raw_date_stripped) {
|
||||||
|
let now = Utc::now();
|
||||||
|
let amount = capture.name("amount")?.as_str().parse::<i64>().ok()?;
|
||||||
|
let unit = capture.name("unit")?.as_str();
|
||||||
|
|
||||||
|
let multiplier = UNIT_VALUES_MAP.get(&unit)?.clone() as i64;
|
||||||
|
let seconds_elapsed = amount * multiplier;
|
||||||
|
|
||||||
|
let publish_date = now - TimeDelta::seconds(seconds_elapsed);
|
||||||
|
|
||||||
|
Some(publish_date)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn slice_remaining_block(&mut self, start_position: &usize) {
|
pub fn slice_remaining_block(&mut self, start_position: &usize) {
|
||||||
let previous_block_bytes = self.previous_block.as_bytes().to_vec();
|
let previous_block_bytes = self.previous_block.as_bytes().to_vec();
|
||||||
let remaining_bytes = previous_block_bytes[*start_position..].to_vec();
|
let remaining_bytes = previous_block_bytes[*start_position..].to_vec();
|
||||||
@ -142,6 +222,7 @@ pub mod engine_base {
|
|||||||
&mut self,
|
&mut self,
|
||||||
single_result_regex: &Regex,
|
single_result_regex: &Regex,
|
||||||
engine: SearchEngine,
|
engine: SearchEngine,
|
||||||
|
date_format: Option<&str>,
|
||||||
) -> Option<SearchResult> {
|
) -> Option<SearchResult> {
|
||||||
if self.started {
|
if self.started {
|
||||||
if let Some(capture) = single_result_regex.captures(&self.previous_block.to_owned())
|
if let Some(capture) = single_result_regex.captures(&self.previous_block.to_owned())
|
||||||
@ -157,12 +238,43 @@ pub mod engine_base {
|
|||||||
let url = decode(capture.name("url").unwrap().as_str())
|
let url = decode(capture.name("url").unwrap().as_str())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.into_owned();
|
.into_owned();
|
||||||
|
let image = match capture.name("image") {
|
||||||
|
Some(image) => Some(image.as_str().to_string()),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut publish_date: Option<SearchResultDate> = None;
|
||||||
|
|
||||||
|
if date_format.is_some() {
|
||||||
|
let date = capture.name("date");
|
||||||
|
publish_date = match date {
|
||||||
|
Some(date) => {
|
||||||
|
match DateTime::parse_from_str(date.as_str(), date_format.unwrap())
|
||||||
|
{
|
||||||
|
Ok(parsed_date) => Some(SearchResultDate {
|
||||||
|
date: parsed_date.to_utc(),
|
||||||
|
is_relative: false,
|
||||||
|
}),
|
||||||
|
Err(_) => match EnginePositions::parse_date(&date.as_str()) {
|
||||||
|
Some(parsed_date) => Some(SearchResultDate {
|
||||||
|
date: parsed_date.to_utc(),
|
||||||
|
is_relative: true,
|
||||||
|
}),
|
||||||
|
None => None,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
let result = SearchResult {
|
let result = SearchResult {
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
url,
|
url,
|
||||||
engine,
|
engine,
|
||||||
|
image_url: image,
|
||||||
|
date: publish_date,
|
||||||
};
|
};
|
||||||
|
|
||||||
let end_position = capture.get(0).unwrap().end();
|
let end_position = capture.get(0).unwrap().end();
|
||||||
|
86
src/main.rs
86
src/main.rs
@ -1,15 +1,18 @@
|
|||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
|
use ahash::AHashSet;
|
||||||
use engines::bing::bing::Bing;
|
use engines::bing::bing::Bing;
|
||||||
use engines::brave::brave::Brave;
|
use engines::brave::brave::Brave;
|
||||||
use engines::duckduckgo::duckduckgo::DuckDuckGo;
|
use engines::duckduckgo::duckduckgo::DuckDuckGo;
|
||||||
use engines::engine_base::engine_base::SearchResult;
|
use engines::engine_base::engine_base::SearchResult;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use regex::Regex;
|
use rocket::form::Form;
|
||||||
use rocket::response::content::{RawCss, RawHtml};
|
use rocket::response::content::{RawCss, RawHtml};
|
||||||
use rocket::response::stream::TextStream;
|
use rocket::response::stream::TextStream;
|
||||||
use rocket::time::Instant;
|
use rocket::time::Instant;
|
||||||
use static_files::static_files::{render_beginning_html, render_finished_css};
|
use static_files::static_files::{
|
||||||
|
render_beginning_html, render_finished_css, render_result, render_result_engine_visibility,
|
||||||
|
};
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
|
|
||||||
use crate::static_files::static_files::read_file_contents;
|
use crate::static_files::static_files::read_file_contents;
|
||||||
@ -25,26 +28,8 @@ pub mod utils;
|
|||||||
extern crate rocket;
|
extern crate rocket;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref HTML_BEGINNING: String =
|
|
||||||
read_file_contents("./src/public/html/beginning.html").unwrap();
|
|
||||||
static ref SET_VALUE_REPLACE: Regex = Regex::new(r#"\{\% search_value \%\}"#).unwrap();
|
|
||||||
static ref HTML_END: String = read_file_contents("./src/public/html/end.html").unwrap();
|
static ref HTML_END: String = read_file_contents("./src/public/html/end.html").unwrap();
|
||||||
static ref TAILWIND_CSS: String = read_file_contents("./src/public/css/style.css").unwrap();
|
static ref TAILWIND_CSS: String = read_file_contents("./src/public/css/style.css").unwrap();
|
||||||
static ref FINISHED_CSS: String = read_file_contents("./src/public/css/finished.css").unwrap();
|
|
||||||
static ref FINISHED_NAME_REPLACE: Regex = Regex::new(r#"(__engine__)"#).unwrap();
|
|
||||||
static ref FINISHED_TIME_REPLACE: Regex = Regex::new(r#"{% time %}"#).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[get("/search")]
|
|
||||||
fn search_get() -> &'static str {
|
|
||||||
"<html>
|
|
||||||
<body>
|
|
||||||
<form method='get' action='/searchquery'>
|
|
||||||
<input name='query'>
|
|
||||||
<button type='submit'>Search</button>
|
|
||||||
</form>
|
|
||||||
</body>
|
|
||||||
</html>"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/style.css")]
|
#[get("/style.css")]
|
||||||
@ -52,8 +37,29 @@ fn get_tailwindcss() -> RawCss<&'static str> {
|
|||||||
RawCss(&TAILWIND_CSS)
|
RawCss(&TAILWIND_CSS)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/searchquery?<query>")]
|
#[get("/")]
|
||||||
async fn hello<'a>(query: &str) -> RawHtml<TextStream![String]> {
|
async fn search_get() -> RawHtml<&'static str> {
|
||||||
|
RawHtml(include_str!("./public/html/frontpage.html"))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(FromForm)]
|
||||||
|
struct Body {
|
||||||
|
query: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! search {
|
||||||
|
($engine:ident,$query_ref:expr,$tx_ref:expr) => {{
|
||||||
|
tokio::spawn(async move {
|
||||||
|
let mut engine = $engine::new();
|
||||||
|
|
||||||
|
engine.search($query_ref, $tx_ref).await
|
||||||
|
})
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[post("/", data = "<body>")]
|
||||||
|
async fn search_post<'a>(body: Form<Body>) -> RawHtml<TextStream![String]> {
|
||||||
|
let query = &body.query;
|
||||||
let query_brave = query.to_owned().clone();
|
let query_brave = query.to_owned().clone();
|
||||||
let query_duckduckgo = query.to_owned().clone();
|
let query_duckduckgo = query.to_owned().clone();
|
||||||
let query_bing = query.to_owned().clone();
|
let query_bing = query.to_owned().clone();
|
||||||
@ -72,31 +78,25 @@ async fn hello<'a>(query: &str) -> RawHtml<TextStream![String]> {
|
|||||||
|
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
|
|
||||||
let brave_task = tokio::spawn(async move {
|
let brave_task = search!(Brave, &query_brave, tx_brave);
|
||||||
let mut brave = Brave::new();
|
let bing_task = search!(Bing, &query_bing, tx_bing);
|
||||||
|
let duckduckgo_task = search!(DuckDuckGo, &query_duckduckgo, tx_duckduckgo);
|
||||||
brave.search(&query_brave, tx_brave).await;
|
|
||||||
});
|
|
||||||
|
|
||||||
let duckduckgo_task = tokio::spawn(async move {
|
|
||||||
let mut duckduckgo = DuckDuckGo::new();
|
|
||||||
|
|
||||||
duckduckgo.search(&query_duckduckgo, tx_duckduckgo).await;
|
|
||||||
});
|
|
||||||
|
|
||||||
let bing_task = tokio::spawn(async move {
|
|
||||||
let mut bing = Bing::new();
|
|
||||||
|
|
||||||
bing.search(&query_bing, tx_bing).await;
|
|
||||||
});
|
|
||||||
|
|
||||||
let beginning_html = render_beginning_html(&query);
|
let beginning_html = render_beginning_html(&query);
|
||||||
|
|
||||||
|
let mut results: AHashSet<String> = AHashSet::new();
|
||||||
|
|
||||||
RawHtml(TextStream! {
|
RawHtml(TextStream! {
|
||||||
yield beginning_html;
|
yield beginning_html;
|
||||||
|
|
||||||
while !brave_task.is_finished() || !duckduckgo_task.is_finished() || !bing_task.is_finished() {
|
while !brave_task.is_finished() || !duckduckgo_task.is_finished() || !bing_task.is_finished() {
|
||||||
while let Some(result) = rx.recv().await {
|
while let Some(result) = rx.recv().await {
|
||||||
|
if results.contains(&result.url) {
|
||||||
|
yield render_result_engine_visibility(&result.get_html_id(), &result.engine);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if !first_result_yielded {
|
if !first_result_yielded {
|
||||||
let diff = first_result_start.elapsed().whole_milliseconds();
|
let diff = first_result_start.elapsed().whole_milliseconds();
|
||||||
first_result_yielded = true;
|
first_result_yielded = true;
|
||||||
@ -123,9 +123,10 @@ async fn hello<'a>(query: &str) -> RawHtml<TextStream![String]> {
|
|||||||
yield render_finished_css("duckduckgo", now.elapsed().whole_milliseconds());
|
yield render_finished_css("duckduckgo", now.elapsed().whole_milliseconds());
|
||||||
}
|
}
|
||||||
|
|
||||||
let text = format!("<li><h1>{}</h1><p>{}</p><i>{}</i></li>", &result.title, &result.description, &result.engine.to_string());
|
yield render_result(&result);
|
||||||
|
yield render_result_engine_visibility(&result.get_html_id(), &result.engine);
|
||||||
|
|
||||||
yield text.to_string();
|
results.insert(result.url.to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,7 +152,6 @@ async fn hello<'a>(query: &str) -> RawHtml<TextStream![String]> {
|
|||||||
#[launch]
|
#[launch]
|
||||||
async fn rocket() -> _ {
|
async fn rocket() -> _ {
|
||||||
rocket::build()
|
rocket::build()
|
||||||
.mount("/", routes![hello])
|
.mount("/", routes![search_post, search_get])
|
||||||
.mount("/", routes![search_get])
|
|
||||||
.mount("/", routes![get_tailwindcss])
|
.mount("/", routes![get_tailwindcss])
|
||||||
}
|
}
|
||||||
|
@ -108,30 +108,12 @@ header {
|
|||||||
height: 2em;
|
height: 2em;
|
||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
}
|
|
||||||
|
|
||||||
li {
|
|
||||||
list-style: none;
|
|
||||||
background: #222;
|
|
||||||
padding: 1em;
|
|
||||||
margin: 1em 0;
|
|
||||||
border-radius: 0.5em;
|
|
||||||
animation: moveIn 0.5s;
|
|
||||||
}
|
|
||||||
|
|
||||||
li h1 {
|
|
||||||
color: #fff;
|
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
font-size: 1.2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
li p {
|
|
||||||
color: #aaa;
|
|
||||||
line-height: 1.5;
|
|
||||||
font-size: 0.9rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
li.fake {
|
li.fake {
|
||||||
|
background: #222;
|
||||||
|
border-radius: 0.5em;
|
||||||
height: 6em;
|
height: 6em;
|
||||||
animation: fakeShimmer 0.8s infinite linear;
|
animation: fakeShimmer 0.8s infinite linear;
|
||||||
}
|
}
|
||||||
@ -178,3 +160,131 @@ li.fake.small {
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#front-search {
|
||||||
|
min-width: 20em;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
padding: 1em 1.6em;
|
||||||
|
border: none;
|
||||||
|
border-radius: 10em;
|
||||||
|
background: #555;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
#frontage {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result {
|
||||||
|
list-style: none;
|
||||||
|
margin: 1em 0;
|
||||||
|
animation: moveIn 0.5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result article {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result .content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5em;
|
||||||
|
justify-content: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result a {
|
||||||
|
padding: 1em;
|
||||||
|
text-decoration: none;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5em;
|
||||||
|
|
||||||
|
background: #222;
|
||||||
|
border-radius: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result .url {
|
||||||
|
/* Show max of 1 line */
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 1;
|
||||||
|
line-clamp: 1;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result a:visited {
|
||||||
|
background: #444;
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result h3 {
|
||||||
|
color: #fff;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result p {
|
||||||
|
color: #aaa;
|
||||||
|
line-height: 1.5;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result small {
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result .search-engines {
|
||||||
|
display: flex;
|
||||||
|
gap: 1em;
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result .search-engines>li {
|
||||||
|
list-style: none;
|
||||||
|
opacity: 0;
|
||||||
|
color: #aaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result .image {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
background: #333;
|
||||||
|
border-radius: .5em;
|
||||||
|
width: 3em;
|
||||||
|
height: 3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result .image .round {
|
||||||
|
width: 2em;
|
||||||
|
height: 2em;
|
||||||
|
margin: .5em;
|
||||||
|
border-radius: .5em;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result .image img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
/* Hide broken image icon */
|
||||||
|
-moz-force-broken-image-icon: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result .image img::after {
|
||||||
|
content: " ";
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
display: block;
|
||||||
|
background-size: contain;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-color: #333;
|
||||||
|
}
|
||||||
|
@ -10,12 +10,14 @@
|
|||||||
|
|
||||||
<body>
|
<body>
|
||||||
<header>
|
<header>
|
||||||
<form id="search-input" action="/searchquery" method="get">
|
<form id="search-input" method="post">
|
||||||
<svg id="back-button" xmlns="http://www.w3.org/2000/svg"
|
<a id="back-button">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg"
|
||||||
viewBox="0 0 448 512"><!--!Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.-->
|
viewBox="0 0 448 512"><!--!Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.-->
|
||||||
<path
|
<path
|
||||||
d="M9.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L109.2 288 416 288c17.7 0 32-14.3 32-32s-14.3-32-32-32l-306.7 0L214.6 118.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-160 160z" />
|
d="M9.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L109.2 288 416 288c17.7 0 32-14.3 32-32s-14.3-32-32-32l-306.7 0L214.6 118.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-160 160z" />
|
||||||
</svg>
|
</svg>
|
||||||
|
</a>
|
||||||
<input id="search" name="query" type="search" placeholder="Search" value="{% search_value %}">
|
<input id="search" name="query" type="search" placeholder="Search" value="{% search_value %}">
|
||||||
</form>
|
</form>
|
||||||
<div id="search-status">
|
<div id="search-status">
|
||||||
@ -225,13 +227,13 @@
|
|||||||
<main>
|
<main>
|
||||||
<div id="results">
|
<div id="results">
|
||||||
<ul>
|
<ul>
|
||||||
<li class="fake small"></li>
|
<li class="result fake small"></li>
|
||||||
<li class="fake big"></li>
|
<li class="result fake big"></li>
|
||||||
<li class="fake"></li>
|
<li class="result fake"></li>
|
||||||
<li class="fake"></li>
|
<li class="result fake"></li>
|
||||||
<li class="fake small"></li>
|
<li class="result fake small"></li>
|
||||||
<li class="fake"></li>
|
<li class="result fake"></li>
|
||||||
<li class="fake"></li>
|
<li class="result fake"></li>
|
||||||
<!-- </ul> -->
|
<!-- </ul> -->
|
||||||
<!-- </div> -->
|
<!-- </div> -->
|
||||||
<!-- </main> -->
|
<!-- </main> -->
|
||||||
|
19
src/public/html/frontpage.html
Normal file
19
src/public/html/frontpage.html
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>tifsep</title>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link href="style.css" rel="stylesheet">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<main id="frontpage">
|
||||||
|
<form method="post">
|
||||||
|
<input id="front-search" name="query" type="search" autofocus>
|
||||||
|
</form>
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
31
src/public/html/result.html
Normal file
31
src/public/html/result.html
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<li class="result" id="__ID__">
|
||||||
|
<a href="{% url %}" target="_blank" rel="noopener noreferrer nofollower">
|
||||||
|
<article>
|
||||||
|
<div class="image">
|
||||||
|
<!-- We need to add a separate div that adds the roundness,
|
||||||
|
as directly rounding the <img> tag will cause a the
|
||||||
|
broken, misaligned image to be visible when
|
||||||
|
the fallback image is shown. -->
|
||||||
|
<div class="round">
|
||||||
|
<img src="{% image_url %}" alt="🌐" loading="lazy">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<small class="url">{% url %}</small>
|
||||||
|
<h3>{% title %}</h3>
|
||||||
|
<p>{% description %}</p>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
<ul class="search-engines">
|
||||||
|
<li class="bing">Bing</li>
|
||||||
|
<li class="duckduckgo">DuckDuckGo</li>
|
||||||
|
<li class="brave">Brave</li>
|
||||||
|
</ul>
|
||||||
|
<small>{% date %}</small>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<style>
|
||||||
|
#__ID__ .image img::after {
|
||||||
|
background-image: url("https://{% url_host %}/favicon.ico");
|
||||||
|
}
|
||||||
|
</style>
|
17
src/rocket_requests.rs
Normal file
17
src/rocket_requests.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
struct UserAgent(String);
|
||||||
|
|
||||||
|
// impl<'a, 'r> FromRequest<'a, 'r> for Token {
|
||||||
|
// type Error = Infallible;
|
||||||
|
//
|
||||||
|
// fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
|
||||||
|
// let token = request.headers().get_one("token");
|
||||||
|
// match token {
|
||||||
|
// Some(token) => {
|
||||||
|
// // check validity
|
||||||
|
// Outcome::Success(Token(token.to_string()))
|
||||||
|
// },
|
||||||
|
// // token does not exist
|
||||||
|
// None => Outcome::Failure(Status::Unauthorized)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
@ -1,10 +1,18 @@
|
|||||||
pub mod static_files {
|
pub mod static_files {
|
||||||
use lazy_static::lazy_static;
|
|
||||||
use std::{
|
use std::{
|
||||||
|
fmt::Debug,
|
||||||
fs::File,
|
fs::File,
|
||||||
|
hash::Hash,
|
||||||
io::{Error, Read},
|
io::{Error, Read},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use reqwest::Url;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
engines::engine_base::engine_base::{SearchEngine, SearchResult},
|
||||||
|
utils::utils::hash_string,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn read_file_contents(path: &str) -> Result<String, Error> {
|
pub fn read_file_contents(path: &str) -> Result<String, Error> {
|
||||||
let mut contents = String::new();
|
let mut contents = String::new();
|
||||||
|
|
||||||
@ -15,11 +23,7 @@ pub mod static_files {
|
|||||||
Ok(contents)
|
Ok(contents)
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
const HTML_BEGINNING: &str = include_str!("./public/html/beginning.html");
|
||||||
static ref HTML_BEGINNING: String =
|
|
||||||
read_file_contents("./src/public/html/beginning.html").unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
const HTML_BEGINNING_QUERY_REPLACE: &str = r#"{% search_value %}"#;
|
const HTML_BEGINNING_QUERY_REPLACE: &str = r#"{% search_value %}"#;
|
||||||
|
|
||||||
pub fn render_beginning_html(query: &str) -> String {
|
pub fn render_beginning_html(query: &str) -> String {
|
||||||
@ -29,17 +33,47 @@ pub mod static_files {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
const FINISHED_CSS: &str = include_str!("./public/css/finished.css");
|
||||||
static ref FINISHED_CSS: String =
|
|
||||||
read_file_contents("./src/public/css/finished.css").unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn render_finished_css(engine: &str, time: i128) -> String {
|
pub fn render_finished_css(engine: &str, time: i128) -> String {
|
||||||
format!(
|
format!(
|
||||||
"<style>{}</style>",
|
"<style>{}</style>",
|
||||||
FINISHED_CSS
|
FINISHED_CSS
|
||||||
.replace("__engine__", engine)
|
.replace("__engine__", engine)
|
||||||
.replace("{% time %}", &format!("{}ms", &time.to_string()))
|
.replace("{% time %}", &time.to_string())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const HTML_RESULT: &str = include_str!("./public/html/result.html");
|
||||||
|
|
||||||
|
pub fn render_result(result: &SearchResult) -> String {
|
||||||
|
HTML_RESULT
|
||||||
|
.replace("{% title %}", &result.title)
|
||||||
|
.replace("{% url %}", &result.url)
|
||||||
|
.replace(
|
||||||
|
"{% url_host %}",
|
||||||
|
Url::parse(&result.url).unwrap().host_str().unwrap(),
|
||||||
|
)
|
||||||
|
.replace("{% description %}", &result.description)
|
||||||
|
.replace("__ID__", &result.get_html_id())
|
||||||
|
.replace(
|
||||||
|
"{% image_url %}",
|
||||||
|
&result.image_url.clone().unwrap_or("".to_string()),
|
||||||
|
)
|
||||||
|
.replace(
|
||||||
|
"{% date %}",
|
||||||
|
&(match &result.date {
|
||||||
|
Some(date_info) => date_info.date.format("%d. %B %Y").to_string(),
|
||||||
|
None => "".to_string(),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render_result_engine_visibility(id: &str, engine: &SearchEngine) -> String {
|
||||||
|
format!(
|
||||||
|
"<style>#{} .search-engines .{} {{ opacity: 1 !important; }}</style>",
|
||||||
|
id,
|
||||||
|
engine.to_string().to_lowercase()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user