more match data

This commit is contained in:
Robin Appelman 2025-04-18 19:28:04 +02:00
commit 0f86fda710
2 changed files with 78 additions and 3 deletions

View file

@ -1,9 +1,10 @@
use super::Parser;
use crate::data::{MatchInfo, TeamRef};
use crate::data::{GameMode, MatchInfo, TeamRef};
use crate::parser::{select_last_text, select_text, team_id_from_link, ElementExt};
use crate::{ParseError, Result};
use scraper::{Html, Selector};
const SELECTOR_MATCH_FORMAT: &str = "h3.page-header > strong.styleColor";
const SELECTOR_MATCH_COMMENT_AUTHOR: &str = ".row-fluid .col-md-12 span.text-success";
const SELECTOR_MATCH_COMMENT: &str = ".row-fluid .col-md-12 > .white-row-light-small > p";
const SELECTOR_MATCH_TEAM_LINK: &str = "a[href^=\"team_page\"]:not(.btn-large)";
@ -11,13 +12,20 @@ const SELECTOR_MATCH_RESULT_TEAM: &str =
".table.table-condensed.table-bordered tr:nth-child(2) td:nth-child(1)";
const SELECTOR_MATCH_RESULT_SCORE: &str =
".table.table-condensed.table-bordered tr:nth-child(2) td:nth-child(2)";
const SELECTOR_MATCH_MAP: &str = "h4.text-success.text-center > b";
const SELECTOR_MATCH_WEEK: &str = "p.muted.text-center.nomargin > small > b:nth-child(1)";
const SELECTOR_MATCH_DATE: &str = "p.muted.text-center.nomargin > small > b:nth-child(2)";
pub struct MatchPageParser {
selector_format: Selector,
selector_author: Selector,
selector_comment: Selector,
selector_team_link: Selector,
selector_result_team: Selector,
selector_result_score: Selector,
selector_map: Selector,
selector_week: Selector,
selector_date: Selector,
}
impl Default for MatchPageParser {
@ -29,11 +37,15 @@ impl Default for MatchPageParser {
impl MatchPageParser {
pub fn new() -> Self {
MatchPageParser {
selector_format: Selector::parse(SELECTOR_MATCH_FORMAT).unwrap(),
selector_author: Selector::parse(SELECTOR_MATCH_COMMENT_AUTHOR).unwrap(),
selector_comment: Selector::parse(SELECTOR_MATCH_COMMENT).unwrap(),
selector_team_link: Selector::parse(SELECTOR_MATCH_TEAM_LINK).unwrap(),
selector_result_team: Selector::parse(SELECTOR_MATCH_RESULT_TEAM).unwrap(),
selector_result_score: Selector::parse(SELECTOR_MATCH_RESULT_SCORE).unwrap(),
selector_map: Selector::parse(SELECTOR_MATCH_MAP).unwrap(),
selector_week: Selector::parse(SELECTOR_MATCH_WEEK).unwrap(),
selector_date: Selector::parse(SELECTOR_MATCH_DATE).unwrap(),
}
}
}
@ -59,6 +71,46 @@ impl Parser for MatchPageParser {
let home_team_id = team_id_from_link(team_link_home.attr("href").unwrap_or_default())?;
let away_team_id = team_id_from_link(team_link_away.attr("href").unwrap_or_default())?;
let format_text = select_text(document.root_element(), &self.selector_format).ok_or(
ParseError::ElementNotFound {
selector: SELECTOR_MATCH_FORMAT,
role: "away team map",
},
)?;
let format = format_text
.parse::<GameMode>()
.ok()
.or_else(|| format_text.split(' ').find_map(|text| text.parse().ok()))
.ok_or_else(|| ParseError::InvalidText {
text: format_text.into(),
role: "match format",
})?;
let map = select_text(document.root_element(), &self.selector_map).ok_or(
ParseError::ElementNotFound {
selector: SELECTOR_MATCH_MAP,
role: "away team map",
},
)?;
let week_text = select_text(document.root_element(), &self.selector_week).ok_or(
ParseError::ElementNotFound {
selector: SELECTOR_MATCH_WEEK,
role: "away team week",
},
)?;
let week: u8 = week_text.parse().map_err(|_| ParseError::InvalidText {
text: week_text.into(),
role: "match week",
})?;
let date = select_text(document.root_element(), &self.selector_date).ok_or(
ParseError::ElementNotFound {
selector: SELECTOR_MATCH_DATE,
role: "away team week",
},
)?;
let mut team_names = document.select(&self.selector_result_team);
let team_name_home = team_names
.next()
@ -133,6 +185,10 @@ impl Parser for MatchPageParser {
name: team_name_away.to_string(),
id: away_team_id,
},
week,
map: map.into(),
default_date: date.into(),
format,
})
}
}

View file

@ -325,7 +325,7 @@ pub struct MatchInfo {
pub map: String,
pub week: u8,
pub format: GameMode,
pub default_date: Date,
pub default_date: String,
}
#[derive(Debug, Clone, Error)]
@ -334,7 +334,7 @@ pub struct InvalidGameMode {
pub text: String,
}
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
#[cfg_attr(feature = "sqlx", sqlx(type_name = "game_mode"))]
#[cfg_attr(feature = "sqlx", sqlx(rename_all = "lowercase"))]
@ -346,6 +346,8 @@ pub enum GameMode {
Ultiduo,
Ones,
FFFours,
Classic,
Left4Dead,
}
impl FromStr for GameMode {
@ -359,17 +361,30 @@ impl FromStr for GameMode {
"4v4" => Ok(GameMode::Fours),
"2v2" => Ok(GameMode::Ultiduo),
"1v1" => Ok(GameMode::Ones),
"Highlander" => Ok(GameMode::Highlander),
"TF2 Highlander" => Ok(GameMode::Highlander),
"ASIA TF2-H" => Ok(GameMode::Highlander),
"ASIA TF2-6" => Ok(GameMode::Sixes),
"ASIA TF2-4" => Ok(GameMode::Fours),
"TF2 8vs8" => Ok(GameMode::Eights),
"8vs8" => Ok(GameMode::Eights),
"TF2 6vs6" => Ok(GameMode::Sixes),
"6vs6" => Ok(GameMode::Sixes),
"TF2 4vs4" => Ok(GameMode::Fours),
"4vs4" => Ok(GameMode::Fours),
"TF2 2vs2" => Ok(GameMode::Ultiduo),
"2vs2" => Ok(GameMode::Ultiduo),
"TF2 Sol 1vs1" => Ok(GameMode::Ones),
"ff4v4" => Ok(GameMode::FFFours),
"FF 4vs4 OvsD" => Ok(GameMode::FFFours),
"Fortress Forever 4vs4 OvsD" => Ok(GameMode::FFFours),
"Team Fortress Classic ADL" => Ok(GameMode::Classic),
"TeamFortressClassic" => Ok(GameMode::Classic),
"classic" => Ok(GameMode::Classic),
"Left For Dead" => Ok(GameMode::Left4Dead),
"Left 4 Dead 2 Versus League" => Ok(GameMode::Left4Dead),
"l4d" => Ok(GameMode::Left4Dead),
"Team Fortress 2 Soldier 1 vs 1 Tournament" => Ok(GameMode::Ones),
_ => Err(InvalidGameMode {
text: s.to_string(),
}),
@ -387,6 +402,8 @@ impl GameMode {
GameMode::Ultiduo => "2",
GameMode::Ones => "1",
GameMode::FFFours => "ff4",
GameMode::Classic => "classic",
GameMode::Left4Dead => "l4d",
}
}
@ -399,6 +416,8 @@ impl GameMode {
GameMode::Ultiduo => "2v2",
GameMode::Ones => "1v1",
GameMode::FFFours => "ff4v4",
GameMode::Classic => "classic",
GameMode::Left4Dead => "l4d",
}
}