2023-03-29 18:17:29 +00:00
|
|
|
use once_cell::sync::Lazy;
|
2023-03-29 21:39:10 +00:00
|
|
|
use rand::seq::SliceRandom;
|
|
|
|
use std::io::BufRead;
|
2023-03-29 18:17:29 +00:00
|
|
|
|
2023-03-29 21:39:10 +00:00
|
|
|
static FONTS: &[&str] = &[
|
|
|
|
"Albura/Albura-Regular.ttf",
|
2023-03-29 18:17:29 +00:00
|
|
|
"AmaticSC-Bold.ttf",
|
|
|
|
"Exo-Regular.otf",
|
|
|
|
"EBGaramond08-Regular.otf",
|
|
|
|
"Gidole-Regular.ttf",
|
2023-03-29 21:39:10 +00:00
|
|
|
"Londrina/LondrinaBook-Regular.otf",
|
|
|
|
"PlayenSans/PlayenSans-Regular.otf",
|
2023-03-29 18:17:29 +00:00
|
|
|
"Playfulist.otf",
|
|
|
|
"ProzaLibre-Regular.ttf",
|
|
|
|
];
|
|
|
|
|
2023-03-29 21:39:10 +00:00
|
|
|
static USER_AGENTS: &[&str] = &[
|
|
|
|
r"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36",
|
|
|
|
r"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36",
|
|
|
|
r"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36",
|
|
|
|
r"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.44",
|
|
|
|
r"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36",
|
|
|
|
r"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36",
|
|
|
|
r"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/111.0",
|
|
|
|
r"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36",
|
|
|
|
r"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36",
|
|
|
|
r"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/111.0",
|
|
|
|
r"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36",
|
|
|
|
];
|
|
|
|
|
2023-03-29 18:17:29 +00:00
|
|
|
static WORDS: Lazy<Vec<String>> = Lazy::new(|| {
|
|
|
|
let file = std::fs::File::open("lefff-3.4.mlex").unwrap();
|
|
|
|
let file_buf = std::io::BufReader::new(file);
|
2023-03-29 21:39:10 +00:00
|
|
|
|
2023-03-29 18:17:29 +00:00
|
|
|
let mut words = Vec::new();
|
|
|
|
for line in file_buf.lines() {
|
|
|
|
let line = line.unwrap();
|
2023-03-29 21:39:10 +00:00
|
|
|
if line.as_bytes().first() != Some(&b't') {
|
|
|
|
continue;
|
2023-03-29 18:17:29 +00:00
|
|
|
}
|
|
|
|
let mut cols = line.split('\t');
|
|
|
|
let Some(word) = cols.next() else {
|
|
|
|
continue
|
|
|
|
};
|
|
|
|
let class = cols.next();
|
|
|
|
match class {
|
|
|
|
Some("nc") => {}
|
|
|
|
Some("adj") => {
|
|
|
|
let Some(flex) = cols.nth(1) else {
|
|
|
|
continue
|
|
|
|
};
|
|
|
|
if flex.contains('p') || flex.contains('m') {
|
2023-03-29 21:39:10 +00:00
|
|
|
continue;
|
2023-03-29 18:17:29 +00:00
|
|
|
}
|
|
|
|
}
|
2023-03-29 21:39:10 +00:00
|
|
|
_ => continue,
|
2023-03-29 18:17:29 +00:00
|
|
|
}
|
|
|
|
let mut capitalized = String::from("T");
|
|
|
|
capitalized.push_str(&word[1..]);
|
|
|
|
words.push(capitalized);
|
|
|
|
}
|
|
|
|
//eprintln!("Words: {}", words.len());
|
|
|
|
words
|
|
|
|
});
|
|
|
|
|
|
|
|
#[tokio::main]
|
|
|
|
async fn main() {
|
|
|
|
Lazy::force(&WORDS);
|
2023-03-29 21:39:10 +00:00
|
|
|
|
2023-03-29 18:17:29 +00:00
|
|
|
tide::log::start();
|
|
|
|
let mut app = tide::new();
|
2023-03-29 21:39:10 +00:00
|
|
|
|
|
|
|
app.at("/").get(handle_request);
|
|
|
|
|
|
|
|
app.listen(std::net::SocketAddr::new(
|
|
|
|
std::net::IpAddr::V4(std::net::Ipv4Addr::new(127, 0, 0, 1)),
|
|
|
|
8137,
|
|
|
|
))
|
|
|
|
.await
|
|
|
|
.unwrap();
|
2023-03-29 18:17:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
async fn handle_request<'a>(_req: tide::Request<()>) -> tide::Result<tide::Response> {
|
|
|
|
let mut rng = rand::thread_rng();
|
|
|
|
let word = WORDS.choose(&mut rng).unwrap();
|
2023-03-29 21:39:10 +00:00
|
|
|
|
2023-03-29 18:17:29 +00:00
|
|
|
let client = reqwest::blocking::Client::builder()
|
2023-03-29 21:39:10 +00:00
|
|
|
.user_agent(*USER_AGENTS.choose(&mut rng).unwrap())
|
|
|
|
.build()
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
let resp = match client
|
|
|
|
.get(format!(
|
|
|
|
"https://www.bing.com/images/search?q={word}&FORM=HDRSC3"
|
|
|
|
))
|
|
|
|
.send()
|
|
|
|
{
|
|
|
|
Ok(resp) => resp,
|
|
|
|
Err(e) => {
|
|
|
|
eprintln!("Error requesting: {e:?}");
|
|
|
|
return Ok(tide::Response::builder(500)
|
|
|
|
.content_type(tide::http::mime::PLAIN)
|
|
|
|
.body("Error requesting search engine")
|
|
|
|
.build());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
if !resp.status().is_success() {
|
|
|
|
eprintln!("Search engine status: {}", resp.status());
|
|
|
|
return Ok(tide::Response::builder(500)
|
|
|
|
.content_type(tide::http::mime::PLAIN)
|
|
|
|
.body(format!("Search engine status: {}", resp.status()))
|
|
|
|
.build());
|
|
|
|
}
|
|
|
|
let page = match resp.text() {
|
|
|
|
Ok(page) => page,
|
|
|
|
Err(e) => {
|
|
|
|
eprintln!("Error getting text: {e:?}");
|
|
|
|
return Ok(tide::Response::builder(500)
|
|
|
|
.content_type(tide::http::mime::PLAIN)
|
|
|
|
.body("Error reading search result")
|
|
|
|
.build());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-03-29 18:17:29 +00:00
|
|
|
let pattern = r#"mediaurl="#;
|
2023-03-29 21:39:10 +00:00
|
|
|
let url_start = match page.find(pattern) {
|
|
|
|
Some(idx) => idx,
|
|
|
|
None => {
|
|
|
|
eprintln!("Error: cannot find pattern");
|
|
|
|
return Ok(tide::Response::builder(500)
|
|
|
|
.content_type(tide::http::mime::PLAIN)
|
|
|
|
.body("Error: pattern not found in search result")
|
|
|
|
.build());
|
|
|
|
}
|
|
|
|
} + pattern.len();
|
|
|
|
let Some(url_len) = page[url_start..].find('&') else {
|
|
|
|
eprintln!("Error: cannot find url end");
|
|
|
|
return Ok(tide::Response::builder(500)
|
|
|
|
.content_type(tide::http::mime::PLAIN)
|
|
|
|
.body("Error: url end not found in search result")
|
|
|
|
.build());
|
|
|
|
};
|
2023-03-29 18:17:29 +00:00
|
|
|
if url_len > 1024 {
|
2023-03-29 21:39:10 +00:00
|
|
|
eprintln!("Error: url too long {url_len}");
|
|
|
|
return Ok(tide::Response::builder(500)
|
|
|
|
.content_type(tide::http::mime::PLAIN)
|
|
|
|
.body("Error: url too long in search result")
|
|
|
|
.build());
|
2023-03-29 18:17:29 +00:00
|
|
|
}
|
2023-03-29 21:39:10 +00:00
|
|
|
let img_url_encoded = &page[url_start..url_start + url_len];
|
|
|
|
let img_url = match percent_encoding::percent_decode_str(img_url_encoded).decode_utf8() {
|
|
|
|
Ok(img_url) => img_url,
|
|
|
|
Err(e) => {
|
|
|
|
eprintln!("Error: percent decoding url {e:?}");
|
|
|
|
return Ok(tide::Response::builder(500)
|
|
|
|
.content_type(tide::http::mime::PLAIN)
|
|
|
|
.body("Error: cannot decode url from search result")
|
|
|
|
.build());
|
|
|
|
}
|
|
|
|
};
|
2023-03-29 18:17:29 +00:00
|
|
|
if img_url.contains('"') {
|
|
|
|
panic!("url contains quotes");
|
|
|
|
}
|
|
|
|
let font = *FONTS.choose(&mut rng).unwrap();
|
2023-03-29 21:39:10 +00:00
|
|
|
|
2023-03-29 18:17:29 +00:00
|
|
|
Ok(tide::Response::builder(200)
|
|
|
|
.header("Access-Control-Allow-Origin", "*")
|
|
|
|
.header("Access-Control-Allow-Headers", "*")
|
|
|
|
.content_type(tide::http::mime::HTML)
|
|
|
|
.body(format!(r#"<!doctype html>
|
|
|
|
<html lang="fr">
|
|
|
|
<head>
|
|
|
|
<meta charset="utf-8"/>
|
|
|
|
<title>MLeTomatic</title>
|
2023-03-31 22:40:54 +00:00
|
|
|
<!--<script type="text/javascript" src="//txmn.tk/js/jquery.js"></script>-->
|
2023-03-29 18:17:29 +00:00
|
|
|
<style type="text/css">
|
|
|
|
@font-face {{
|
|
|
|
font-family: CustomFont;
|
|
|
|
src: url("//txmn.tk/fonts/{font}");
|
|
|
|
}}
|
|
|
|
body {{
|
|
|
|
text-align: center;
|
|
|
|
}}
|
2023-03-31 22:40:54 +00:00
|
|
|
h1, #pitch {{
|
2023-03-29 18:17:29 +00:00
|
|
|
font-family: CustomFont;
|
|
|
|
font-weight: normal;
|
|
|
|
}}
|
|
|
|
#img {{
|
|
|
|
max-width: 100%;
|
|
|
|
max-height: 100vh;
|
|
|
|
}}
|
|
|
|
</style>
|
|
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<h1>Monnaie Libre et {word}</h1>
|
2023-03-31 22:40:54 +00:00
|
|
|
<!--<p id="pitch"><noscript>Active JavaScript pour découvrir pourquoi tu devrais rejoindre l'association Monnaie Libre et {word} !</noscript></p>-->
|
2023-03-29 18:17:29 +00:00
|
|
|
<img id="img" alt="{word}" src="{img_url}"/>
|
2023-03-29 21:39:10 +00:00
|
|
|
<div id="info">
|
2023-03-31 22:40:54 +00:00
|
|
|
<p><a href="https://git.txmn.tk/tuxmain/MLeTomatic">MLeTomatic</a>, parce qu'on ne fait pas d'mlet sans casser des nœuds – Images trouvées par Bing, soumises au droit d'auteur. Mots tirés de Lefff, lire la licence dans le dépôt.</p>
|
2023-03-29 21:39:10 +00:00
|
|
|
</div>
|
2023-03-31 22:40:54 +00:00
|
|
|
<script type="text/javascript">
|
|
|
|
/*window.onload = function() {{
|
|
|
|
$.ajax({{
|
|
|
|
method: "POST",
|
|
|
|
url: "https://api.openai.com/v1/engines/text-davinci-003/completions",
|
|
|
|
data: JSON.stringify({{
|
|
|
|
"prompt":"Rédige un court flyer pour l'association \"Monnaie Libre et {word}\", en accentuant l'aspect \"{word}\".",
|
|
|
|
"max_tokens":250,
|
|
|
|
"temperature":1,
|
|
|
|
"top_p":1,
|
|
|
|
"n":1,
|
|
|
|
"stream":false,
|
|
|
|
"echo":false,
|
|
|
|
"presence_penalty":0,
|
|
|
|
"frequency_penalty":0,
|
|
|
|
"best_of":1
|
|
|
|
}}),
|
|
|
|
success: function(resp) {{
|
|
|
|
document.getElementById("pitch").innerHTML = resp.choices[0].text;
|
|
|
|
}},
|
|
|
|
dataType: "json",
|
|
|
|
contentType: "application/json; charset=utf-8"
|
|
|
|
}});
|
|
|
|
}};*/
|
|
|
|
</script>
|
2023-03-29 18:17:29 +00:00
|
|
|
</body>
|
|
|
|
</html>"#))
|
|
|
|
.build())
|
|
|
|
}
|