mirror of
https://github.com/natsukagami/youmubot.git
synced 2025-04-16 07:18:54 +00:00
Merge branch 'fix-empty-user'
This commit is contained in:
commit
d68ce9cec8
3 changed files with 92 additions and 72 deletions
|
@ -10,6 +10,7 @@ use rayon::prelude::*;
|
||||||
use serenity::{
|
use serenity::{
|
||||||
framework::standard::{CommandError as Error, CommandResult},
|
framework::standard::{CommandError as Error, CommandResult},
|
||||||
http::CacheHttp,
|
http::CacheHttp,
|
||||||
|
model::id::{ChannelId, UserId},
|
||||||
CacheAndHttp,
|
CacheAndHttp,
|
||||||
};
|
};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -23,53 +24,69 @@ pub fn updates(c: Arc<CacheAndHttp>, d: AppData, channels: MemberToChannels) ->
|
||||||
let osu = d.get_cloned::<OsuClient>();
|
let osu = d.get_cloned::<OsuClient>();
|
||||||
// For each user...
|
// For each user...
|
||||||
let mut data = OsuSavedUsers::open(&*d.read()).borrow()?.clone();
|
let mut data = OsuSavedUsers::open(&*d.read()).borrow()?.clone();
|
||||||
'user_loop: for (user_id, osu_user) in data.iter_mut() {
|
for (user_id, osu_user) in data.iter_mut() {
|
||||||
let mut pp_values = vec![]; // Store the pp values here...
|
let channels = channels.channels_of(c.clone(), *user_id);
|
||||||
for mode in &[Mode::Std, Mode::Taiko, Mode::Catch, Mode::Mania] {
|
if channels.is_empty() {
|
||||||
let scores = scan_user(&osu, osu_user, *mode)?;
|
continue; // We don't wanna update an user without any active server
|
||||||
let user = match osu.user(UserID::ID(osu_user.id), |f| f.mode(*mode)) {
|
}
|
||||||
Ok(Some(u)) => u,
|
osu_user.pp = match (&[Mode::Std, Mode::Taiko, Mode::Catch, Mode::Mania])
|
||||||
_ => continue 'user_loop,
|
.par_iter()
|
||||||
};
|
.map(|m| handle_user_mode(c.clone(), &osu, &osu_user, *user_id, &channels[..], *m))
|
||||||
pp_values.push(user.pp);
|
.collect::<Result<_, _>>()
|
||||||
if scores.is_empty() && !osu_user.pp.is_empty() {
|
{
|
||||||
// Nothing to update: no new scores and pp is there.
|
Ok(v) => v,
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("osu: Cannot update {}: {}", osu_user.id, e.0);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
scores
|
};
|
||||||
.into_par_iter()
|
|
||||||
.filter_map(|(rank, score)| {
|
|
||||||
let beatmap = osu
|
|
||||||
.beatmaps(BeatmapRequestKind::Beatmap(score.beatmap_id), |f| f)
|
|
||||||
.map(|v| BeatmapWithMode(v.into_iter().next().unwrap(), *mode));
|
|
||||||
let channels = channels.channels_of(c.clone(), *user_id);
|
|
||||||
match beatmap {
|
|
||||||
Ok(v) => Some((rank, score, v, channels)),
|
|
||||||
Err(e) => {
|
|
||||||
dbg!(e);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.for_each(|(rank, score, beatmap, channels)| {
|
|
||||||
for channel in channels {
|
|
||||||
if let Err(e) = channel.send_message(c.http(), |c| {
|
|
||||||
c.content(format!("New top record from {}!", user_id.mention()))
|
|
||||||
.embed(|e| score_embed(&score, &beatmap, &user, Some(rank), e))
|
|
||||||
}) {
|
|
||||||
dbg!(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
osu_user.last_update = chrono::Utc::now();
|
osu_user.last_update = chrono::Utc::now();
|
||||||
osu_user.pp = pp_values;
|
|
||||||
}
|
}
|
||||||
// Update users
|
// Update users
|
||||||
*OsuSavedUsers::open(&*d.read()).borrow_mut()? = data;
|
*OsuSavedUsers::open(&*d.read()).borrow_mut()? = data;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Handles an user/mode scan, announces all possible new scores, return the new pp value.
|
||||||
|
fn handle_user_mode(
|
||||||
|
c: Arc<CacheAndHttp>,
|
||||||
|
osu: &Osu,
|
||||||
|
osu_user: &OsuUser,
|
||||||
|
user_id: UserId,
|
||||||
|
channels: &[ChannelId],
|
||||||
|
mode: Mode,
|
||||||
|
) -> Result<Option<f64>, Error> {
|
||||||
|
let scores = scan_user(osu, osu_user, mode)?;
|
||||||
|
let user = osu
|
||||||
|
.user(UserID::ID(osu_user.id), |f| f.mode(mode))?
|
||||||
|
.ok_or(Error::from("user not found"))?;
|
||||||
|
scores
|
||||||
|
.into_par_iter()
|
||||||
|
.filter_map(|(rank, score)| {
|
||||||
|
let beatmap = osu
|
||||||
|
.beatmaps(BeatmapRequestKind::Beatmap(score.beatmap_id), |f| f)
|
||||||
|
.map(|v| BeatmapWithMode(v.into_iter().next().unwrap(), mode));
|
||||||
|
match beatmap {
|
||||||
|
Ok(v) => Some((rank, score, v)),
|
||||||
|
Err(e) => {
|
||||||
|
dbg!(e);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.for_each(|(rank, score, beatmap)| {
|
||||||
|
for channel in (&channels).iter() {
|
||||||
|
if let Err(e) = channel.send_message(c.http(), |c| {
|
||||||
|
c.content(format!("New top record from {}!", user_id.mention()))
|
||||||
|
.embed(|e| score_embed(&score, &beatmap, &user, Some(rank), e))
|
||||||
|
}) {
|
||||||
|
dbg!(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Ok(user.pp)
|
||||||
|
}
|
||||||
|
|
||||||
fn scan_user(osu: &Osu, u: &OsuUser, mode: Mode) -> Result<Vec<(u8, Score)>, Error> {
|
fn scan_user(osu: &Osu, u: &OsuUser, mode: Mode) -> Result<Vec<(u8, Score)>, Error> {
|
||||||
let scores = osu.user_best(UserID::ID(u.id), |f| f.mode(mode).limit(25))?;
|
let scores = osu.user_best(UserID::ID(u.id), |f| f.mode(mode).limit(25))?;
|
||||||
let scores = scores
|
let scores = scores
|
||||||
|
|
|
@ -75,23 +75,26 @@ impl TryFrom<raw::User> for User {
|
||||||
username: raw.username,
|
username: raw.username,
|
||||||
joined: parse_date(&raw.join_date)?,
|
joined: parse_date(&raw.join_date)?,
|
||||||
country: raw.country,
|
country: raw.country,
|
||||||
count_300: parse_from_str(&raw.count300)?,
|
count_300: raw.count300.map(parse_from_str).unwrap_or(Ok(0))?,
|
||||||
count_100: parse_from_str(&raw.count100)?,
|
count_100: raw.count100.map(parse_from_str).unwrap_or(Ok(0))?,
|
||||||
count_50: parse_from_str(&raw.count50)?,
|
count_50: raw.count50.map(parse_from_str).unwrap_or(Ok(0))?,
|
||||||
play_count: parse_from_str(&raw.playcount)?,
|
play_count: raw.playcount.map(parse_from_str).unwrap_or(Ok(0))?,
|
||||||
played_time: parse_duration(&raw.total_seconds_played)?,
|
played_time: raw
|
||||||
ranked_score: parse_from_str(&raw.ranked_score)?,
|
.total_seconds_played
|
||||||
total_score: parse_from_str(&raw.total_score)?,
|
.map(parse_duration)
|
||||||
count_ss: parse_from_str(&raw.count_rank_ss)?,
|
.unwrap_or(Ok(Duration::from_secs(0)))?,
|
||||||
count_ssh: parse_from_str(&raw.count_rank_ssh)?,
|
ranked_score: raw.ranked_score.map(parse_from_str).unwrap_or(Ok(0))?,
|
||||||
count_s: parse_from_str(&raw.count_rank_s)?,
|
total_score: raw.total_score.map(parse_from_str).unwrap_or(Ok(0))?,
|
||||||
count_sh: parse_from_str(&raw.count_rank_sh)?,
|
count_ss: raw.count_rank_ss.map(parse_from_str).unwrap_or(Ok(0))?,
|
||||||
count_a: parse_from_str(&raw.count_rank_a)?,
|
count_ssh: raw.count_rank_ssh.map(parse_from_str).unwrap_or(Ok(0))?,
|
||||||
rank: parse_from_str(&raw.pp_rank)?,
|
count_s: raw.count_rank_s.map(parse_from_str).unwrap_or(Ok(0))?,
|
||||||
country_rank: parse_from_str(&raw.pp_country_rank)?,
|
count_sh: raw.count_rank_sh.map(parse_from_str).unwrap_or(Ok(0))?,
|
||||||
level: parse_from_str(&raw.level)?,
|
count_a: raw.count_rank_a.map(parse_from_str).unwrap_or(Ok(0))?,
|
||||||
pp: Some(parse_from_str(&raw.pp_raw)?).filter(|v| *v != 0.0),
|
rank: raw.pp_rank.map(parse_from_str).unwrap_or(Ok(0))?,
|
||||||
accuracy: parse_from_str(&raw.accuracy)?,
|
country_rank: raw.pp_country_rank.map(parse_from_str).unwrap_or(Ok(0))?,
|
||||||
|
level: raw.level.map(parse_from_str).unwrap_or(Ok(0.0))?,
|
||||||
|
pp: Some(raw.pp_raw.map(parse_from_str).unwrap_or(Ok(0.0))?).filter(|v| *v != 0.0),
|
||||||
|
accuracy: raw.accuracy.map(parse_from_str).unwrap_or(Ok(0.0))?,
|
||||||
events: {
|
events: {
|
||||||
let mut v = Vec::new();
|
let mut v = Vec::new();
|
||||||
for e in raw.events.into_iter() {
|
for e in raw.events.into_iter() {
|
||||||
|
|
|
@ -46,24 +46,24 @@ pub(crate) struct User {
|
||||||
pub user_id: String,
|
pub user_id: String,
|
||||||
pub username: String,
|
pub username: String,
|
||||||
pub join_date: String,
|
pub join_date: String,
|
||||||
pub count300: String,
|
|
||||||
pub count100: String,
|
|
||||||
pub count50: String,
|
|
||||||
pub playcount: String,
|
|
||||||
pub ranked_score: String,
|
|
||||||
pub total_score: String,
|
|
||||||
pub pp_rank: String,
|
|
||||||
pub level: String,
|
|
||||||
pub pp_raw: String,
|
|
||||||
pub accuracy: String,
|
|
||||||
pub count_rank_ss: String,
|
|
||||||
pub count_rank_ssh: String,
|
|
||||||
pub count_rank_s: String,
|
|
||||||
pub count_rank_sh: String,
|
|
||||||
pub count_rank_a: String,
|
|
||||||
pub country: String,
|
pub country: String,
|
||||||
pub total_seconds_played: String,
|
pub count300: Option<String>,
|
||||||
pub pp_country_rank: String,
|
pub count100: Option<String>,
|
||||||
|
pub count50: Option<String>,
|
||||||
|
pub playcount: Option<String>,
|
||||||
|
pub ranked_score: Option<String>,
|
||||||
|
pub total_score: Option<String>,
|
||||||
|
pub pp_rank: Option<String>,
|
||||||
|
pub level: Option<String>,
|
||||||
|
pub pp_raw: Option<String>,
|
||||||
|
pub accuracy: Option<String>,
|
||||||
|
pub count_rank_ss: Option<String>,
|
||||||
|
pub count_rank_ssh: Option<String>,
|
||||||
|
pub count_rank_s: Option<String>,
|
||||||
|
pub count_rank_sh: Option<String>,
|
||||||
|
pub count_rank_a: Option<String>,
|
||||||
|
pub total_seconds_played: Option<String>,
|
||||||
|
pub pp_country_rank: Option<String>,
|
||||||
pub events: Vec<UserEvent>,
|
pub events: Vec<UserEvent>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue