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
|
target
|
||||||
.env
|
.env
|
||||||
*.ron
|
*.toml
|
||||||
cargo-remote
|
cargo-remote
|
||||||
|
|
|
@ -20,6 +20,8 @@ pub use community::COMMUNITY_GROUP;
|
||||||
pub use fun::FUN_GROUP;
|
pub use fun::FUN_GROUP;
|
||||||
pub use osu::OSU_GROUP;
|
pub use osu::OSU_GROUP;
|
||||||
|
|
||||||
|
pub use announcer::Announcer;
|
||||||
|
|
||||||
// A help command
|
// A help command
|
||||||
#[help]
|
#[help]
|
||||||
pub fn 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;
|
pub(crate) mod embeds;
|
||||||
mod hook;
|
mod hook;
|
||||||
|
|
||||||
|
pub use announcer::OsuAnnouncer;
|
||||||
use embeds::{beatmap_embed, score_embed, user_embed};
|
use embeds::{beatmap_embed, score_embed, user_embed};
|
||||||
pub use hook::hook;
|
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.
|
/// A list of SoftBans for all servers.
|
||||||
pub type SoftBans = DB<GuildMap<ServerSoftBans>>;
|
pub type SoftBans = DB<GuildMap<ServerSoftBans>>;
|
||||||
|
|
||||||
|
@ -49,9 +52,10 @@ pub fn setup_db(client: &mut Client) -> Result<(), Error> {
|
||||||
PathBuf::from("data")
|
PathBuf::from("data")
|
||||||
});
|
});
|
||||||
let mut data = client.data.write();
|
let mut data = client.data.write();
|
||||||
SoftBans::insert_into(&mut *data, &path.join("soft_bans.ron"))?;
|
SoftBans::insert_into(&mut *data, &path.join("soft_bans.toml"))?;
|
||||||
OsuSavedUsers::insert_into(&mut *data, &path.join("osu_saved_users.ron"))?;
|
OsuSavedUsers::insert_into(&mut *data, &path.join("osu_saved_users.toml"))?;
|
||||||
OsuLastBeatmap::insert_into(&mut *data, &path.join("last_beatmaps.ron"))?;
|
OsuLastBeatmap::insert_into(&mut *data, &path.join("last_beatmaps.toml"))?;
|
||||||
|
AnnouncerChannels::insert_into(&mut *data, &path.join("announcers.toml"))?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,9 @@ mod commands;
|
||||||
mod db;
|
mod db;
|
||||||
mod http;
|
mod http;
|
||||||
|
|
||||||
|
use commands::osu::OsuAnnouncer;
|
||||||
|
use commands::Announcer;
|
||||||
|
|
||||||
const MESSAGE_HOOKS: [fn(&mut Context, &Message) -> (); 1] = [commands::osu::hook];
|
const MESSAGE_HOOKS: [fn(&mut Context, &Message) -> (); 1] = [commands::osu::hook];
|
||||||
|
|
||||||
struct Handler;
|
struct Handler;
|
||||||
|
@ -54,6 +57,9 @@ fn main() {
|
||||||
// Create handler threads
|
// Create handler threads
|
||||||
std::thread::spawn(commands::admin::watch_soft_bans(&mut client));
|
std::thread::spawn(commands::admin::watch_soft_bans(&mut client));
|
||||||
|
|
||||||
|
// Announcers
|
||||||
|
OsuAnnouncer::scan(&client, std::time::Duration::from_secs(60));
|
||||||
|
|
||||||
println!("Starting...");
|
println!("Starting...");
|
||||||
if let Err(v) = client.start() {
|
if let Err(v) = client.start() {
|
||||||
panic!(v)
|
panic!(v)
|
||||||
|
|
Loading…
Add table
Reference in a new issue