mirror of
https://github.com/natsukagami/youmubot.git
synced 2025-04-18 16:28:55 +00:00
osu! announcer
This commit is contained in:
parent
2820b025b8
commit
33fd152331
6 changed files with 113 additions and 4 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,4 +1,4 @@
|
|||
target
|
||||
.env
|
||||
*.ron
|
||||
*.toml
|
||||
cargo-remote
|
||||
|
|
|
@ -20,6 +20,8 @@ pub use community::COMMUNITY_GROUP;
|
|||
pub use fun::FUN_GROUP;
|
||||
pub use osu::OSU_GROUP;
|
||||
|
||||
pub use announcer::Announcer;
|
||||
|
||||
// A help command
|
||||
#[help]
|
||||
pub fn help(
|
||||
|
|
96
youmubot/src/commands/osu/announcer.rs
Normal file
96
youmubot/src/commands/osu/announcer.rs
Normal file
|
@ -0,0 +1,96 @@
|
|||
use super::{embeds::score_embed, BeatmapWithMode};
|
||||
use crate::{
|
||||
commands::announcer::Announcer,
|
||||
db::{OsuSavedUsers, OsuUser},
|
||||
http::{Osu, HTTP},
|
||||
};
|
||||
use reqwest::blocking::Client as HTTPClient;
|
||||
use serenity::{
|
||||
framework::standard::{CommandError as Error, CommandResult},
|
||||
http::Http,
|
||||
model::{
|
||||
id::{ChannelId, UserId},
|
||||
misc::Mentionable,
|
||||
},
|
||||
prelude::ShareMap,
|
||||
};
|
||||
use youmubot_osu::{
|
||||
models::{Mode, Score},
|
||||
request::{BeatmapRequestKind, UserID},
|
||||
Client as OsuClient,
|
||||
};
|
||||
|
||||
/// Announce osu! top scores.
|
||||
pub struct OsuAnnouncer;
|
||||
|
||||
impl Announcer for OsuAnnouncer {
|
||||
fn announcer_key() -> &'static str {
|
||||
"osu"
|
||||
}
|
||||
fn send_messages(
|
||||
c: &Http,
|
||||
d: &mut ShareMap,
|
||||
channels: impl Fn(UserId) -> Vec<ChannelId>,
|
||||
) -> CommandResult {
|
||||
let http = d.get::<HTTP>().expect("HTTP");
|
||||
let osu = d.get::<Osu>().expect("osu!client");
|
||||
// For each user...
|
||||
let mut data = d
|
||||
.get::<OsuSavedUsers>()
|
||||
.expect("DB initialized")
|
||||
.read(|f| f.clone())?;
|
||||
for (user_id, osu_user) in data.iter_mut() {
|
||||
let mut user = None;
|
||||
for mode in &[Mode::Std, Mode::Taiko, Mode::Mania, Mode::Catch] {
|
||||
let scores = OsuAnnouncer::scan_user(http, osu, osu_user, *mode)?;
|
||||
if scores.is_empty() {
|
||||
continue;
|
||||
}
|
||||
let user = user.get_or_insert_with(|| {
|
||||
osu.user(http, UserID::ID(osu_user.id), |f| f)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
});
|
||||
for (rank, score) in scores {
|
||||
let beatmap = BeatmapWithMode(
|
||||
osu.beatmaps(http, BeatmapRequestKind::Beatmap(score.beatmap_id), |f| f)?
|
||||
.into_iter()
|
||||
.next()
|
||||
.unwrap(),
|
||||
*mode,
|
||||
);
|
||||
for channel in channels(*user_id) {
|
||||
channel.send_message(c, |c| {
|
||||
c.content(format!("New top record from {}!", user_id.mention()))
|
||||
.embed(|e| score_embed(&score, &beatmap, &user, Some(rank), e))
|
||||
})?;
|
||||
}
|
||||
}
|
||||
}
|
||||
osu_user.last_update = chrono::Utc::now();
|
||||
}
|
||||
// Update users
|
||||
let f = d.get_mut::<OsuSavedUsers>().expect("DB initialized");
|
||||
f.write(|f| *f = data)?;
|
||||
f.save()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl OsuAnnouncer {
|
||||
fn scan_user(
|
||||
http: &HTTPClient,
|
||||
osu: &OsuClient,
|
||||
u: &OsuUser,
|
||||
mode: Mode,
|
||||
) -> Result<Vec<(u8, Score)>, Error> {
|
||||
let scores = osu.user_best(http, UserID::ID(u.id), |f| f.mode(mode).limit(25))?;
|
||||
let scores = scores
|
||||
.into_iter()
|
||||
.filter(|s: &Score| s.date >= u.last_update)
|
||||
.enumerate()
|
||||
.map(|(i, v)| (i as u8, v))
|
||||
.collect();
|
||||
Ok(scores)
|
||||
}
|
||||
}
|
|
@ -21,6 +21,7 @@ mod cache;
|
|||
pub(crate) mod embeds;
|
||||
mod hook;
|
||||
|
||||
pub use announcer::OsuAnnouncer;
|
||||
use embeds::{beatmap_embed, score_embed, user_embed};
|
||||
pub use hook::hook;
|
||||
|
||||
|
|
|
@ -33,6 +33,9 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// A map from announcer keys to guild IDs and to channels.
|
||||
pub type AnnouncerChannels = DB<HashMap<String, GuildMap<ChannelId>>>;
|
||||
|
||||
/// A list of SoftBans for all servers.
|
||||
pub type SoftBans = DB<GuildMap<ServerSoftBans>>;
|
||||
|
||||
|
@ -49,9 +52,10 @@ pub fn setup_db(client: &mut Client) -> Result<(), Error> {
|
|||
PathBuf::from("data")
|
||||
});
|
||||
let mut data = client.data.write();
|
||||
SoftBans::insert_into(&mut *data, &path.join("soft_bans.ron"))?;
|
||||
OsuSavedUsers::insert_into(&mut *data, &path.join("osu_saved_users.ron"))?;
|
||||
OsuLastBeatmap::insert_into(&mut *data, &path.join("last_beatmaps.ron"))?;
|
||||
SoftBans::insert_into(&mut *data, &path.join("soft_bans.toml"))?;
|
||||
OsuSavedUsers::insert_into(&mut *data, &path.join("osu_saved_users.toml"))?;
|
||||
OsuLastBeatmap::insert_into(&mut *data, &path.join("last_beatmaps.toml"))?;
|
||||
AnnouncerChannels::insert_into(&mut *data, &path.join("announcers.toml"))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -12,6 +12,9 @@ mod commands;
|
|||
mod db;
|
||||
mod http;
|
||||
|
||||
use commands::osu::OsuAnnouncer;
|
||||
use commands::Announcer;
|
||||
|
||||
const MESSAGE_HOOKS: [fn(&mut Context, &Message) -> (); 1] = [commands::osu::hook];
|
||||
|
||||
struct Handler;
|
||||
|
@ -54,6 +57,9 @@ fn main() {
|
|||
// Create handler threads
|
||||
std::thread::spawn(commands::admin::watch_soft_bans(&mut client));
|
||||
|
||||
// Announcers
|
||||
OsuAnnouncer::scan(&client, std::time::Duration::from_secs(60));
|
||||
|
||||
println!("Starting...");
|
||||
if let Err(v) = client.start() {
|
||||
panic!(v)
|
||||
|
|
Loading…
Add table
Reference in a new issue