feat(scraper): getuser fetching done

This commit is contained in:
Maieul BOYER 2026-02-08 17:01:27 +01:00
parent 73fe9b85a3
commit e57bb34a35
Signed by: maix
SSH key fingerprint: SHA256:iqCzqFFF5KjRixmDExqbAltCIj9ndlBWIGJf3t9Ln9g
6 changed files with 131 additions and 2 deletions

22
Cargo.lock generated
View file

@ -276,7 +276,10 @@ dependencies = [
"reqwest",
"scraper",
"secrecy",
"serde",
"serde_json",
"smol_str",
"thiserror 2.0.18",
"tokio",
"url",
]
@ -1305,6 +1308,19 @@ dependencies = [
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.149"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
dependencies = [
"itoa",
"memchr",
"serde",
"serde_core",
"zmij",
]
[[package]]
name = "servo_arc"
version = "0.4.3"
@ -2197,3 +2213,9 @@ dependencies = [
"quote",
"syn",
]
[[package]]
name = "zmij"
version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ff05f8caa9038894637571ae6b9e29466c1f4f829d26c9b28f869a29cbe3445"

View file

@ -8,7 +8,10 @@ constcat = "0.6.1"
reqwest = "0.13.1"
scraper = "0.25.0"
secrecy = "0.10.3"
smol_str = "0.3.5"
serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0.149"
smol_str = { version = "0.3.5", features = ["serde"] }
thiserror = "2.0.18"
url = "2.5.8"
[dev-dependencies]

View file

@ -30,7 +30,7 @@ async fn main() {
)
}
froxy_scrapper::types::ClusterLocationData::Normal { status } => {
//eprintln!("[{:<10}] {status:?}", l.location)
// eprintln!("[{:<10}] {status:?}", l.location)
}
}
}

View file

@ -0,0 +1,14 @@
use froxy_scrapper::{state::State, types::ClusterLocation};
#[tokio::main(flavor = "current_thread")]
async fn main() {
let session = std::env::var("FROXY_COOKIE")
.expect("provide `FROXY_COOKIE` with the session cookie from you friends42 instance");
let state = State::new(session);
for a in std::env::args().skip(1) {
let res = state.getuser(&a).await.unwrap();
serde_json::to_writer_pretty(&mut std::io::stdout(), &res).unwrap();
println!();
}
}

View file

@ -135,4 +135,40 @@ impl State {
self.request(Method::POST, url.as_ref(), qs, Some(body))
.await
}
pub async fn getuser(&self, name: &str) -> Result<Option<crate::types::Profile>, GetUserError> {
let req = self.get(format!("/getuser/{name}"), None).await?;
let text = req.text().await?;
let json = serde_json::from_str::<crate::types::ProfileRaw>(&text)?;
Ok(Some(crate::types::Profile {
admin: json.admin,
campus: json.campus,
id: json.id,
userid: json.userid,
pool: json.pool.filter(|s| !s.contains("None")),
image: json.image,
image_medium: json.image_medium,
is_friend: match json.is_friend {
crate::types::IsFriend::U32(u) => u != 0,
crate::types::IsFriend::Bool(b) => b,
},
lang: json.lang,
name: json.name,
position: json.position,
active: json.active,
website: json.website.filter(|s| !s.is_empty()),
recit: json.recit.filter(|s| !s.is_empty()),
discord: json.discord.filter(|s| !s.is_empty()),
github: json.github.filter(|s| !s.is_empty()),
}))
}
}
#[derive(Debug, thiserror::Error)]
pub enum GetUserError {
#[error("RequestError: {0}")]
RequestError(#[from] reqwest::Error),
#[error("JsonError: {0}")]
JsonError(#[from] serde_json::Error),
}

View file

@ -61,3 +61,57 @@ pub struct Friend {
pub struct Friends {
pub friends: Vec<Friend>,
}
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
#[serde(untagged)]
pub(crate) enum IsFriend {
U32(u32),
Bool(bool),
}
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
pub(crate) struct ProfileRaw {
pub(crate) admin: bool,
pub(crate) active: Option<SmolStr>,
pub(crate) campus: u64,
pub(crate) id: u64,
pub(crate) userid: Option<u64>,
pub(crate) image: String,
pub(crate) image_medium: String,
pub(crate) is_friend: IsFriend,
pub(crate) lang: SmolStr,
pub(crate) name: SmolStr,
pub(crate) pool: Option<SmolStr>,
pub(crate) position: Option<SmolStr>,
pub(crate) recit: Option<String>,
pub(crate) website: Option<String>,
pub(crate) discord: Option<String>,
pub(crate) github: Option<String>,
}
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
pub struct Profile {
pub admin: bool,
pub campus: u64,
pub id: u64,
pub userid: Option<u64>,
pub pool: Option<SmolStr>,
pub image: String,
pub image_medium: String,
pub is_friend: bool,
pub lang: SmolStr,
pub name: SmolStr,
pub position: Option<SmolStr>,
pub active: Option<SmolStr>,
pub website: Option<String>,
pub recit: Option<String>,
pub discord: Option<String>,
pub github: Option<String>,
}