osu_api/util/
v1.rs

1use crate::api_v1::{
2  Error as ApiError, GetBeatmapsProps, GetBeatmapsResp, GetUserRecentProp, GetUserRecentResp,
3  OsuApiRequester, UserId,
4};
5use thiserror::Error;
6
7#[derive(Error, Debug)]
8pub enum Error {
9  #[error("there is no record match your given param")]
10  NotFound,
11  #[error("internal error")]
12  Api(#[from] ApiError),
13}
14
15/// Represent the score and beatmap information
16pub struct LatestReplay {
17  pub score: GetUserRecentResp,
18  pub beatmap: GetBeatmapsResp,
19}
20
21/// Get the latest replay from the given user
22pub async fn get_user_latest_replay<'u, C, U>(
23  client: &C,
24  key: &str,
25  user: U,
26) -> Result<LatestReplay, Error>
27where
28  C: OsuApiRequester,
29  U: Into<UserId<'u>>,
30{
31  let prop = GetUserRecentProp::builder()
32    .api_key(key)
33    .user_info(user)
34    .limit(1)
35    .build();
36
37  let mut resp = client.get_user_recent(prop).await?;
38
39  if resp.is_empty() {
40    return Err(Error::NotFound);
41  }
42
43  let user_recent = resp.swap_remove(0);
44
45  let prop = GetBeatmapsProps::builder()
46    .api_key(key)
47    .beatmap_id(user_recent.beatmap_id)
48    .limit(1)
49    .build();
50
51  let mut resp = client.get_beatmaps(prop).await?;
52
53  if resp.is_empty() {
54    return Err(Error::NotFound);
55  }
56
57  let map_info = resp.swap_remove(0);
58
59  Ok(LatestReplay {
60    score: user_recent,
61    beatmap: map_info,
62  })
63}
64
65/// Generate beatmap cover image URL. Require beatmapset_id not beatmap_id.
66pub fn gen_beatmap_cover_img_url(set_id: u64) -> reqwest::Url {
67  reqwest::Url::parse(&format!(
68    "https://assets.ppy.sh/beatmaps/{set_id}/covers/cover.jpg"
69  ))
70  .unwrap()
71}
72
73/// Generate beatmap thumbnail image URL. Require beatmapset_id not beaetmap_id.
74pub fn gen_beatmap_thumbnail(set_id: u64) -> reqwest::Url {
75  reqwest::Url::parse(&format!("https://b.ppy.sh/thumb/{set_id}l.jpg")).unwrap()
76}