mirror of
https://codeberg.org/icewind/ugc-scaper.git
synced 2026-06-03 18:24:10 +02:00
add player favorite classes
This commit is contained in:
parent
259c2795fd
commit
1ffdc25582
6 changed files with 2605 additions and 2 deletions
33
src/data.rs
33
src/data.rs
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2423
tests/data/player_76561198049312442.html
Normal file
2423
tests/data/player_76561198049312442.html
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -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();
|
||||||
|
|
|
||||||
120
tests/snapshots/snapshot__parse_player_classes_html.snap
Normal file
120
tests/snapshots/snapshot__parse_player_classes_html.snap
Normal 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"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -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": []
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue