add more page metadata

This commit is contained in:
kageru 2023-02-13 11:55:05 +01:00
parent 556bbb3a08
commit cb60970924
3 changed files with 98 additions and 44 deletions

@ -70,12 +70,48 @@ impl Card {
for printing in &self.card_sets { for printing in &self.card_sets {
write!(s, "{}: {} ({})", printing.set_name, printing.set_code, printing.set_rarity)?; write!(s, "{}: {} ({})", printing.set_name, printing.set_code, printing.set_rarity)?;
if let Some(date) = SETS_BY_NAME.get(&printing.set_name.to_lowercase()).and_then(|s| s.tcg_date) { if let Some(date) = SETS_BY_NAME.get(&printing.set_name.to_lowercase()).and_then(|s| s.tcg_date) {
write!(s, " - {}", date)?; write!(s, " - {date}")?;
} }
s.push_str("<br/>"); s.push_str("<br/>");
} }
Ok(s) Ok(s)
} }
pub fn short_info(&self) -> Result<String, fmt::Error> {
let mut s = String::new();
s.push_str(&self.name);
s.push('\n');
self.basic_info(&mut s, "\n")?;
Ok(s)
}
fn basic_info<W: Write>(&self, f: &mut W, newline: &str) -> fmt::Result {
if let Some(level) = self.level {
if self.card_type.contains("XYZ") {
f.write_str("Rank ")?;
} else {
f.write_str("Level ")?;
}
write!(f, "{level} ")?;
} else if let Some(lr) = self.link_rating {
write!(f, "Link {lr} ")?;
}
if let Some(attr) = &self.attribute {
write!(f, "{attr}/")?;
}
write!(f, "{} {}", self.r#type, self.card_type)?;
if self.card_type.contains(&String::from("Monster")) {
f.write_str(newline)?;
match (self.atk, self.def) {
(Some(atk), Some(def)) => write!(f, "{atk} ATK / {def} DEF")?,
(Some(atk), None) if self.link_rating.is_some() => write!(f, "{atk} ATK")?,
(None, Some(def)) => write!(f, "? ATK / {def} DEF")?,
(Some(atk), None) => write!(f, "{atk} ATK / ? DEF")?,
(None, None) => write!(f, "? ATK / ? DEF")?,
}
}
Ok(())
}
} }
impl Display for Card { impl Display for Card {
@ -92,30 +128,7 @@ impl Display for Card {
_ => String::new(), _ => String::new(),
} }
)?; )?;
if let Some(level) = self.level { self.basic_info(f, "<br/>")?;
if self.card_type.contains("XYZ") {
f.write_str("Rank ")?;
} else {
f.write_str("Level ")?;
}
write!(f, "{level} ")?;
} else if let Some(lr) = self.link_rating {
write!(f, "Link {lr} ")?;
}
if let Some(attr) = &self.attribute {
write!(f, "{attr}/")?;
}
write!(f, "{} {}", self.r#type, self.card_type)?;
if self.card_type.contains(&String::from("Monster")) {
f.write_str("<br/>")?;
match (self.atk, self.def) {
(Some(atk), Some(def)) => write!(f, "{atk} ATK / {def} DEF")?,
(Some(atk), None) if self.link_rating.is_some() => write!(f, "{atk} ATK")?,
(None, Some(def)) => write!(f, "? ATK / {def} DEF")?,
(Some(atk), None) => write!(f, "{atk} ATK / ? DEF")?,
(None, None) => write!(f, "? ATK / ? DEF")?,
}
}
write!(f, "</em><p>{}</p>", &self.text)?; write!(f, "</em><p>{}</p>", &self.text)?;
Ok(()) Ok(())
} }

@ -59,9 +59,10 @@ struct Query {
#[derive(Debug)] #[derive(Debug)]
struct PageData { struct PageData {
title: String, description: String,
query: Option<String>, title: String,
body: String, query: Option<String>,
body: String,
} }
const HEADER: &str = include_str!("../static/header.html"); const HEADER: &str = include_str!("../static/header.html");
@ -84,7 +85,12 @@ async fn search(q: Option<Either<web::Query<Query>, web::Form<Query>>>) -> AnyRe
let mut res = String::with_capacity(10_000); let mut res = String::with_capacity(10_000);
let data = match q { let data = match q {
Some(q) => compute_results(q)?, Some(q) => compute_results(q)?,
None => PageData { title: "YGO card search".to_owned(), query: None, body: "Enter a query above to search".to_owned() }, None => PageData {
title: "YGO card search".to_owned(),
description: "Enter a query above to search".to_owned(),
query: None,
body: "Enter a query above to search".to_owned(),
},
}; };
add_data(&mut res, &data)?; add_data(&mut res, &data)?;
Ok(HttpResponse::Ok().insert_header(header::ContentType::html()).body(res)) Ok(HttpResponse::Ok().insert_header(header::ContentType::html()).body(res))
@ -95,16 +101,23 @@ async fn card_info(card_id: web::Path<usize>) -> AnyResult<HttpResponse> {
let mut res = String::with_capacity(2_000); let mut res = String::with_capacity(2_000);
let data = match CARDS_BY_ID.get(&card_id) { let data = match CARDS_BY_ID.get(&card_id) {
Some(card) => PageData { Some(card) => PageData {
title: format!("{} - YGO Card Database", card.name), title: format!("{} - YGO Card Database", card.name),
query: None, description: card.short_info()?,
body: format!( query: None,
r#"<div><img class="fullimage" src="{}/static/full/{}.jpg"/>{card}{}</div>"#, body: format!(
r#"<div> <img alt="Card Image: {}" class="fullimage" src="{}/static/full/{}.jpg"/>{card} {} </div>"#,
card.name,
IMG_HOST.as_str(), IMG_HOST.as_str(),
card.id, card.id,
card.extended_info().unwrap_or_else(|_| String::new()), card.extended_info().unwrap_or_else(|_| String::new()),
), ),
}, },
None => PageData { title: "Card not found - YGO Card Database".to_owned(), query: None, body: "Card not found".to_owned() }, None => PageData {
description: "Card not found - YGO Card Database".to_owned(),
title: "Card not found - YGO Card Database".to_owned(),
query: None,
body: "Card not found".to_owned(),
},
}; };
add_data(&mut res, &data)?; add_data(&mut res, &data)?;
Ok(HttpResponse::Ok().insert_header(header::ContentType::html()).body(res)) Ok(HttpResponse::Ok().insert_header(header::ContentType::html()).body(res))
@ -113,7 +126,12 @@ async fn card_info(card_id: web::Path<usize>) -> AnyResult<HttpResponse> {
#[get("/help")] #[get("/help")]
async fn help() -> AnyResult<HttpResponse> { async fn help() -> AnyResult<HttpResponse> {
let mut res = String::with_capacity(HEADER.len() + HELP_CONTENT.len() + FOOTER.len() + 250); let mut res = String::with_capacity(HEADER.len() + HELP_CONTENT.len() + FOOTER.len() + 250);
let data = PageData { query: None, title: "Query Syntax - YGO Card Database".to_owned(), body: HELP_CONTENT.to_owned() }; let data = PageData {
query: None,
title: "Query Syntax - YGO Card Database".to_owned(),
body: HELP_CONTENT.to_owned(),
description: String::new(),
};
add_data(&mut res, &data)?; add_data(&mut res, &data)?;
Ok(HttpResponse::Ok().insert_header(header::ContentType::html()).body(res)) Ok(HttpResponse::Ok().insert_header(header::ContentType::html()).body(res))
} }
@ -124,7 +142,8 @@ fn add_searchbox(res: &mut String, query: &Option<String>) -> std::fmt::Result {
r#" r#"
<form action="/"> <form action="/">
<input type="text" name="q" id="searchbox" placeholder="Enter query (e.g. l:5 c:synchro atk>2000)" value="{}"><input type="submit" id="submit" value="🔍"> <input type="text" name="q" id="searchbox" placeholder="Enter query (e.g. l:5 c:synchro atk>2000)" value="{}"><input type="submit" id="submit" value="🔍">
</form>"#, </form>
"#,
match &query { match &query {
Some(q) => q.replace('"', "&quot;"), Some(q) => q.replace('"', "&quot;"),
None => String::new(), None => String::new(),
@ -138,7 +157,12 @@ fn compute_results(raw_query: String) -> AnyResult<PageData> {
Ok(q) => q, Ok(q) => q,
Err(e) => { Err(e) => {
let s = format!("Could not parse query: {e:?}"); let s = format!("Could not parse query: {e:?}");
return Ok(PageData { title: s.clone(), query: Some(raw_query), body: s }); return Ok(PageData {
description: s.clone(),
query: Some(raw_query),
body: s,
title: "YGO Card Database".to_owned(),
});
} }
}; };
let now = Instant::now(); let now = Instant::now();
@ -151,24 +175,37 @@ fn compute_results(raw_query: String) -> AnyResult<PageData> {
let readable_query = format!("Showing {} results where {}", matches.len(), raw_filters.iter().map(|f| f.to_string()).join(" and "),); let readable_query = format!("Showing {} results where {}", matches.len(), raw_filters.iter().map(|f| f.to_string()).join(" and "),);
write!(body, "<span class=\"meta\">{readable_query} (took {:?})</span>", now.elapsed())?; write!(body, "<span class=\"meta\">{readable_query} (took {:?})</span>", now.elapsed())?;
if matches.is_empty() { if matches.is_empty() {
return Ok(PageData { title: readable_query.clone(), query: Some(raw_query), body }); return Ok(PageData {
description: readable_query,
query: Some(raw_query),
body,
title: "No results - YGO Card Database".to_owned(),
});
} }
body.push_str("<div style=\"display: flex; flex-wrap: wrap;\">"); body.push_str("<div style=\"display: flex; flex-wrap: wrap;\">");
for card in matches { for card in &matches {
write!( write!(
body, body,
r#"<a class="cardresult" href="/card/{}"><img src="{}/static/thumb/{}.jpg" class="thumb"/>{card}</a>"#, r#"<a class="cardresult" href="/card/{}"><img alt="Card Image: {}" src="{}/static/thumb/{}.jpg" class="thumb"/>{card}</a>"#,
card.id, card.id,
card.name,
IMG_HOST.as_str(), IMG_HOST.as_str(),
card.id card.id
)?; )?;
} }
body.push_str("</div>"); body.push_str("</div>");
Ok(PageData { title: readable_query.clone(), query: Some(raw_query), body }) Ok(PageData {
description: readable_query,
query: Some(raw_query),
body,
title: format!("{} results - YGO Card Database", matches.len()),
})
} }
fn add_data(res: &mut String, pd: &PageData) -> AnyResult<()> { fn add_data(res: &mut String, pd: &PageData) -> AnyResult<()> {
res.push_str(&HEADER.replacen("{TITLE}", &pd.title, 1).replacen("{IMG_HOST}", &IMG_HOST, 1)); res.push_str(
&HEADER.replacen("{DESCRIPTION}", &pd.description, 2).replacen("{IMG_HOST}", &IMG_HOST, 1).replacen("{TITLE}", &pd.title, 2),
);
add_searchbox(res, &pd.query)?; add_searchbox(res, &pd.query)?;
res.push_str(&pd.body); res.push_str(&pd.body);
res.push_str(FOOTER); res.push_str(FOOTER);

@ -1,6 +1,10 @@
<html> <html lang="en">
<head> <head>
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta property="og:title" content="{TITLE}" />
<meta property="og:type" content="website" />
<meta name="description" content="{DESCRIPTION}" />
<meta property="og:description" content="{DESCRIPTION}" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<link rel="stylesheet" href="{IMG_HOST}/static/style.css" /> <link rel="stylesheet" href="{IMG_HOST}/static/style.css" />
<title>{TITLE}</title> <title>{TITLE}</title>