add player favorite classes

This commit is contained in:
Robin Appelman 2024-02-23 19:46:32 +01:00
commit 1ffdc25582
6 changed files with 2605 additions and 2 deletions

View file

@ -46,6 +46,7 @@ pub struct Player {
pub steam_id: SteamID, pub steam_id: SteamID,
pub honors: Vec<Honors>, pub honors: Vec<Honors>,
pub teams: Vec<TeamMemberShip>, pub teams: Vec<TeamMemberShip>,
pub favorite_classes: Vec<Class>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -102,6 +103,38 @@ pub struct Team {
pub name_changes: Vec<NameChange>, pub name_changes: Vec<NameChange>,
} }
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
pub enum Class {
Scout,
Soldier,
Pyro,
Demoman,
Heavy,
Medic,
Sniper,
Spy,
}
impl FromStr for Class {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"scout" => Ok(Class::Scout),
"soldier" => Ok(Class::Soldier),
"pyro" => Ok(Class::Pyro),
"demoman" => Ok(Class::Demoman),
"heavy" => Ok(Class::Heavy),
"medic" => Ok(Class::Medic),
"sniper" => Ok(Class::Sniper),
"spy" => Ok(Class::Spy),
_ => Err(()),
}
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub struct NameChange { pub struct NameChange {

View file

@ -1,9 +1,10 @@
use super::{ElementExt, Parser}; use super::{ElementExt, Parser};
use crate::data::{Honors, Player, TeamMemberShip, TeamRef}; use crate::data::{Class, Honors, Player, TeamMemberShip, TeamRef};
use crate::parser::{select_last_text, select_text, team_id_from_link, DATE_FORMAT}; use crate::parser::{select_last_text, select_text, team_id_from_link, DATE_FORMAT};
use crate::{ParseError, Result}; use crate::{ParseError, Result};
use scraper::{Html, Selector}; use scraper::{Html, Selector};
use std::iter::repeat; use std::iter::repeat;
use std::str::FromStr;
use steamid_ng::SteamID; use steamid_ng::SteamID;
use time::Date; use time::Date;
@ -23,6 +24,8 @@ const SELECTOR_PLAYER_TEAM_NAME: &str = "span.text-primary b";
const SELECTOR_PLAYER_TEAM_LEAGUE: &str = "small"; const SELECTOR_PLAYER_TEAM_LEAGUE: &str = "small";
const SELECTOR_PLAYER_TEAM_SINCE: &str = "small"; const SELECTOR_PLAYER_TEAM_SINCE: &str = "small";
const SELECTOR_CLASS: &str = r#"img.img-rounded[src*="images/tf2/icon/"]"#;
pub struct PlayerParser { pub struct PlayerParser {
selector_name: Selector, selector_name: Selector,
selector_id: Selector, selector_id: Selector,
@ -37,6 +40,8 @@ pub struct PlayerParser {
selector_team_name: Selector, selector_team_name: Selector,
selector_team_league: Selector, selector_team_league: Selector,
selector_team_since: Selector, selector_team_since: Selector,
selector_class: Selector,
} }
impl Default for PlayerParser { impl Default for PlayerParser {
@ -61,6 +66,8 @@ impl PlayerParser {
selector_team_name: Selector::parse(SELECTOR_PLAYER_TEAM_NAME).unwrap(), selector_team_name: Selector::parse(SELECTOR_PLAYER_TEAM_NAME).unwrap(),
selector_team_league: Selector::parse(SELECTOR_PLAYER_TEAM_LEAGUE).unwrap(), selector_team_league: Selector::parse(SELECTOR_PLAYER_TEAM_LEAGUE).unwrap(),
selector_team_since: Selector::parse(SELECTOR_PLAYER_TEAM_SINCE).unwrap(), selector_team_since: Selector::parse(SELECTOR_PLAYER_TEAM_SINCE).unwrap(),
selector_class: Selector::parse(SELECTOR_CLASS).unwrap(),
} }
} }
} }
@ -127,6 +134,16 @@ impl Parser for PlayerParser {
}) })
.collect::<Result<Vec<_>>>()?; .collect::<Result<Vec<_>>>()?;
let favorite_classes = document
.select(&self.selector_class)
.filter_map(|class| class.attr("src"))
.filter_map(|img| {
img.strip_prefix("images/tf2/icon/")
.and_then(|class| class.strip_suffix(".jpg"))
})
.filter_map(|class| Class::from_str(class).ok())
.collect::<Vec<_>>();
let teams = document let teams = document
.select(&self.selector_team_group) .select(&self.selector_team_group)
.filter(|item| item.select(&self.selector_team_link).next().is_some()) .filter(|item| item.select(&self.selector_team_link).next().is_some())
@ -192,6 +209,7 @@ impl Parser for PlayerParser {
steam_id: SteamID::from_steam3(&id).unwrap_or_default(), steam_id: SteamID::from_steam3(&id).unwrap_or_default(),
honors, honors,
teams, teams,
favorite_classes,
}) })
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -13,6 +13,14 @@ fn test_parse_player_html() {
assert_json_snapshot!(parsed); assert_json_snapshot!(parsed);
} }
#[test]
fn test_parse_player_classes_html() {
let body = read_to_string("tests/data/player_76561198049312442.html").unwrap();
let parser = PlayerParser::new();
let parsed = parser.parse(&body).unwrap();
assert_json_snapshot!(parsed);
}
#[test] #[test]
fn test_parse_player_details_html() { fn test_parse_player_details_html() {
let body = read_to_string("tests/data/player_details_76561198024494988.html").unwrap(); let body = read_to_string("tests/data/player_details_76561198024494988.html").unwrap();

View file

@ -0,0 +1,120 @@
---
source: tests/snapshot.rs
expression: parsed
---
{
"name": "Dirty Sneeds Don",
"steam_id": 0,
"honors": [
{
"format": "TF2 Highlander",
"season": "Season 32 Euro Platinum",
"team": "Xenon"
},
{
"format": "TF2 Highlander",
"season": "Season 31 Euro Platinum",
"team": "Xenon"
},
{
"format": "TF2 Highlander",
"season": "Season 30 Euro Platinum",
"team": "Xenon"
},
{
"format": "TF2 Highlander",
"season": "Season 29 Euro Platinum",
"team": "Xenon"
},
{
"format": "TF2 Highlander",
"season": "Season 28 Euro Platinum",
"team": "Xenon"
},
{
"format": "TF2 Highlander",
"season": "Season 27 Premium EU",
"team": "Xenon"
},
{
"format": "TF2 Highlander",
"season": "Season 26 Premium EU",
"team": "Xenon"
},
{
"format": "TF2 Highlander",
"season": "Season 25 Euro Platinum",
"team": "Xenon"
},
{
"format": "TF2 Highlander",
"season": "Season 24 Euro Platinum",
"team": "Xenon"
},
{
"format": "TF2 Highlander",
"season": "Season 23 Euro Platinum",
"team": "Xenon"
},
{
"format": "TF2 Highlander",
"season": "Season 22 Euro Platinum",
"team": "Xenon"
},
{
"format": "TF2 Highlander",
"season": "Season 21 Euro Platinum",
"team": "Xenon"
},
{
"format": "TF2 Highlander",
"season": "Season 20 Euro Platinum",
"team": "Xenon"
},
{
"format": "TF2 Highlander",
"season": "Season 19 Euro Gold",
"team": "Xenon"
},
{
"format": "TF2 Highlander",
"season": "Season 18 Euro Silver",
"team": "Xenon"
},
{
"format": "TF2 Highlander",
"season": "Season 17 Euro Silver",
"team": "Xenon"
},
{
"format": "TF2 6vs6",
"season": "Season 32 Europe",
"team": "Ulku Ocaklari"
},
{
"format": "TF2 6vs6",
"season": "Season 31 Europe",
"team": "Ulku Ocaklari"
},
{
"format": "TF2 6vs6",
"season": "Season 30 Europe",
"team": "Ulku Ocaklari"
}
],
"teams": [
{
"team": {
"name": "Xenon",
"id": 7861
},
"league": "TF2 Highlander - Euro Platinum",
"since": "2015-09-23"
}
],
"favorite_classes": [
"demoman",
"soldier",
"scout"
]
}

View file

@ -224,5 +224,6 @@ expression: parsed
"league": "TF2 Highlander - Euro Platinum", "league": "TF2 Highlander - Euro Platinum",
"since": "2013-08-09" "since": "2013-08-09"
} }
] ],
"favorite_classes": []
} }