Update youmubot-osu

This commit is contained in:
Natsu Kagami 2024-02-18 01:03:53 +01:00 committed by Natsu Kagami
parent 2db59905b2
commit 0460e800e5
7 changed files with 229 additions and 218 deletions

View file

@ -9,15 +9,16 @@ use crate::{
Client as Osu, Client as Osu,
}; };
use announcer::MemberToChannels; use announcer::MemberToChannels;
use serenity::builder::CreateMessage;
use serenity::{ use serenity::{
http::CacheHttp, http::CacheHttp,
model::{ model::{
channel::Message, channel::Message,
id::{ChannelId, UserId}, id::{ChannelId, UserId},
}, },
CacheAndHttp,
}; };
use std::{convert::TryInto, sync::Arc}; use std::{convert::TryInto, sync::Arc};
use youmubot_prelude::announcer::CacheAndHttp;
use youmubot_prelude::*; use youmubot_prelude::*;
/// osu! announcer's unique announcer key. /// osu! announcer's unique announcer key.
@ -38,7 +39,7 @@ impl Announcer {
impl youmubot_prelude::Announcer for Announcer { impl youmubot_prelude::Announcer for Announcer {
async fn updates( async fn updates(
&mut self, &mut self,
c: Arc<CacheAndHttp>, c: CacheAndHttp,
d: AppData, d: AppData,
channels: MemberToChannels, channels: MemberToChannels,
) -> Result<()> { ) -> Result<()> {
@ -189,7 +190,7 @@ impl Announcer {
#[derive(Clone)] #[derive(Clone)]
struct Context { struct Context {
data: AppData, data: AppData,
c: Arc<CacheAndHttp>, c: CacheAndHttp,
} }
struct CollectedScore<'a> { struct CollectedScore<'a> {
@ -291,8 +292,10 @@ impl<'a> CollectedScore<'a> {
} }
}; };
let m = channel let m = channel
.send_message(ctx.c.http(), |c| { .send_message(
c.content(match self.kind { ctx.c.http(),
CreateMessage::new()
.content(match self.kind {
ScoreType::TopRecord(_) => { ScoreType::TopRecord(_) => {
format!("New top record from {}!", self.discord_user.mention()) format!("New top record from {}!", self.discord_user.mention())
} }
@ -307,15 +310,15 @@ impl<'a> CollectedScore<'a> {
} }
} }
}) })
.embed(|e| { .embed({
let mut b = score_embed(&self.score, bm, content, self.user); let mut b = score_embed(&self.score, bm, content, self.user);
match self.kind { match self.kind {
ScoreType::TopRecord(rank) => b.top_record(rank), ScoreType::TopRecord(rank) => b.top_record(rank),
ScoreType::WorldRecord(rank) => b.world_record(rank), ScoreType::WorldRecord(rank) => b.world_record(rank),
} }
.build(e) .build()
}) }),
}) )
.await?; .await?;
save_beatmap(&*ctx.data.read().await, channel, bm) save_beatmap(&*ctx.data.read().await, channel, bm)
.await .await

View file

@ -37,7 +37,7 @@ impl OsuSavedUsers {
/// Get an user by their user_id. /// Get an user by their user_id.
pub async fn by_user_id(&self, user_id: UserId) -> Result<Option<OsuUser>> { pub async fn by_user_id(&self, user_id: UserId) -> Result<Option<OsuUser>> {
let mut conn = self.pool.acquire().await?; let mut conn = self.pool.acquire().await?;
let u = model::OsuUser::by_user_id(user_id.0 as i64, &mut *conn) let u = model::OsuUser::by_user_id(user_id.get() as i64, &mut *conn)
.await? .await?
.map(OsuUser::from); .map(OsuUser::from);
Ok(u) Ok(u)
@ -52,7 +52,7 @@ impl OsuSavedUsers {
/// Save the given user as a completely new user. /// Save the given user as a completely new user.
pub async fn new_user(&self, u: OsuUser) -> Result<()> { pub async fn new_user(&self, u: OsuUser) -> Result<()> {
let mut t = self.pool.begin().await?; let mut t = self.pool.begin().await?;
model::OsuUser::delete(u.user_id.0 as i64, &mut *t).await?; model::OsuUser::delete(u.user_id.get() as i64, &mut *t).await?;
model::OsuUser::from(u).store(&mut *t).await?; model::OsuUser::from(u).store(&mut *t).await?;
t.commit().await?; t.commit().await?;
Ok(()) Ok(())
@ -74,7 +74,8 @@ impl OsuLastBeatmap {
impl OsuLastBeatmap { impl OsuLastBeatmap {
pub async fn by_channel(&self, id: impl Into<ChannelId>) -> Result<Option<(Beatmap, Mode)>> { pub async fn by_channel(&self, id: impl Into<ChannelId>) -> Result<Option<(Beatmap, Mode)>> {
let last_beatmap = models::LastBeatmap::by_channel_id(id.into().0 as i64, &self.0).await?; let last_beatmap =
models::LastBeatmap::by_channel_id(id.into().get() as i64, &self.0).await?;
Ok(match last_beatmap { Ok(match last_beatmap {
Some(lb) => Some((bincode::deserialize(&lb.beatmap[..])?, lb.mode.into())), Some(lb) => Some((bincode::deserialize(&lb.beatmap[..])?, lb.mode.into())),
None => None, None => None,
@ -88,7 +89,7 @@ impl OsuLastBeatmap {
mode: Mode, mode: Mode,
) -> Result<()> { ) -> Result<()> {
let b = models::LastBeatmap { let b = models::LastBeatmap {
channel_id: channel.into().0 as i64, channel_id: channel.into().get() as i64,
beatmap: bincode::serialize(beatmap)?, beatmap: bincode::serialize(beatmap)?,
mode: mode as u8, mode: mode as u8,
}; };
@ -121,7 +122,7 @@ impl OsuUserBests {
scores scores
.into_iter() .into_iter()
.map(|score| models::UserBestScore { .map(|score| models::UserBestScore {
user_id: user.0 as i64, user_id: user.get() as i64,
beatmap_id: score.beatmap_id as i64, beatmap_id: score.beatmap_id as i64,
mode: mode as u8, mode: mode as u8,
mods: score.mods.bits() as i64, mods: score.mods.bits() as i64,
@ -151,7 +152,7 @@ pub struct OsuUser {
impl From<OsuUser> for model::OsuUser { impl From<OsuUser> for model::OsuUser {
fn from(u: OsuUser) -> Self { fn from(u: OsuUser) -> Self {
Self { Self {
user_id: u.user_id.0 as i64, user_id: u.user_id.get() as i64,
username: Some(u.username.into_owned()), username: Some(u.username.into_owned()),
id: u.id as i64, id: u.id as i64,
last_update: u.last_update, last_update: u.last_update,
@ -167,7 +168,7 @@ impl From<OsuUser> for model::OsuUser {
impl From<model::OsuUser> for OsuUser { impl From<model::OsuUser> for OsuUser {
fn from(u: model::OsuUser) -> Self { fn from(u: model::OsuUser) -> Self {
Self { Self {
user_id: UserId(u.user_id as u64), user_id: UserId::new(u.user_id as u64),
username: u.username.map(Cow::Owned).unwrap_or("unknown".into()), username: u.username.map(Cow::Owned).unwrap_or("unknown".into()),
id: u.id as u64, id: u.id as u64,
last_update: u.last_update, last_update: u.last_update,

View file

@ -51,6 +51,7 @@ mod scores {
cache::save_beatmap, BeatmapCache, BeatmapMetaCache, BeatmapWithMode, cache::save_beatmap, BeatmapCache, BeatmapMetaCache, BeatmapWithMode,
}; };
use crate::models::{Mode, Score}; use crate::models::{Mode, Score};
use serenity::builder::EditMessage;
use serenity::{framework::standard::CommandResult, model::channel::Message}; use serenity::{framework::standard::CommandResult, model::channel::Message};
use youmubot_prelude::*; use youmubot_prelude::*;
@ -100,13 +101,14 @@ mod scores {
.await? .await?
.ok_or_else(|| Error::msg("user not found"))?; .ok_or_else(|| Error::msg("user not found"))?;
msg.edit(ctx, |e| { msg.edit(
e.embed(|e| { ctx,
EditMessage::new().embed({
crate::discord::embeds::score_embed(score, &bm, &content, &user) crate::discord::embeds::score_embed(score, &bm, &content, &user)
.footer(format!("Page {}/{}", page + 1, self.scores.len())) .footer(format!("Page {}/{}", page + 1, self.scores.len()))
.build(e) .build()
}) }),
}) )
.await?; .await?;
save_beatmap(&*ctx.data.read().await, msg.channel_id, &bm).await?; save_beatmap(&*ctx.data.read().await, msg.channel_id, &bm).await?;
@ -127,6 +129,7 @@ mod scores {
use crate::discord::oppai_cache::Accuracy; use crate::discord::oppai_cache::Accuracy;
use crate::discord::{Beatmap, BeatmapCache, BeatmapInfo, BeatmapMetaCache}; use crate::discord::{Beatmap, BeatmapCache, BeatmapInfo, BeatmapMetaCache};
use crate::models::{Mode, Score}; use crate::models::{Mode, Score};
use serenity::builder::EditMessage;
use serenity::{framework::standard::CommandResult, model::channel::Message}; use serenity::{framework::standard::CommandResult, model::channel::Message};
use youmubot_prelude::*; use youmubot_prelude::*;
@ -327,7 +330,7 @@ mod scores {
self.total_pages() self.total_pages()
)); ));
m.push_line("[?] means pp was predicted by oppai-rs."); m.push_line("[?] means pp was predicted by oppai-rs.");
msg.edit(ctx, |f| f.content(m.to_string())).await?; msg.edit(ctx, EditMessage::new().content(m.to_string())).await?;
hourglass.delete(ctx).await?; hourglass.delete(ctx).await?;
Ok(true) Ok(true)
} }
@ -347,7 +350,7 @@ mod beatmapset {
models::{Beatmap, Mode, Mods}, models::{Beatmap, Mode, Mods},
}; };
use serenity::{ use serenity::{
collector::ReactionAction, model::channel::Message, model::channel::ReactionType, model::channel::Message, model::channel::ReactionType, all::Reaction, builder::{EditMessage, CreateEmbedFooter},
}; };
use youmubot_prelude::*; use youmubot_prelude::*;
@ -418,11 +421,12 @@ mod beatmapset {
) -> Result<bool> { ) -> Result<bool> {
let page = page as usize; let page = page as usize;
if page == self.maps.len() { if page == self.maps.len() {
m.edit(ctx, |f| { m.edit(ctx,
f.embed(|em| { EditMessage::new().embed(crate::discord::embeds::beatmapset_embed(
crate::discord::embeds::beatmapset_embed(&self.maps[..], self.mode, em) &self.maps[..],
}) self.mode,
}) ))
)
.await?; .await?;
return Ok(true); return Ok(true);
} }
@ -439,25 +443,24 @@ mod beatmapset {
info info
} }
}; };
m.edit(ctx, |e| { m.edit(ctx,
e.content(self.message.as_str()).embed(|em| { EditMessage::new().content(self.message.as_str()).embed(
crate::discord::embeds::beatmap_embed( crate::discord::embeds::beatmap_embed(
map, map,
self.mode.unwrap_or(map.mode), self.mode.unwrap_or(map.mode),
self.mods, self.mods,
info, info,
em,
) )
.footer(|f| { .footer( {
f.text(format!( CreateEmbedFooter::new(format!(
"Difficulty {}/{}. To show all difficulties in a single embed (old style), react {}", "Difficulty {}/{}. To show all difficulties in a single embed (old style), react {}",
page + 1, page + 1,
self.maps.len(), self.maps.len(),
SHOW_ALL_EMOTE, SHOW_ALL_EMOTE,
)) ))
}) })
}) )
}) )
.await?; .await?;
save_beatmap( save_beatmap(
&*ctx.data.read().await, &*ctx.data.read().await,
@ -485,13 +488,10 @@ mod beatmapset {
page: u8, page: u8,
ctx: &Context, ctx: &Context,
message: &mut serenity::model::channel::Message, message: &mut serenity::model::channel::Message,
reaction: &ReactionAction, reaction: &Reaction,
) -> Result<Option<u8>> { ) -> Result<Option<u8>> {
// Render the old style. // Render the old style.
let v = match reaction { if let ReactionType::Unicode(s) = &reaction.emoji {
ReactionAction::Added(v) | ReactionAction::Removed(v) => v,
};
if let ReactionType::Unicode(s) = &v.emoji {
if s == SHOW_ALL_EMOTE { if s == SHOW_ALL_EMOTE {
self.render(self.maps.len() as u8, ctx, message).await?; self.render(self.maps.len() as u8, ctx, message).await?;
return Ok(Some(self.maps.len() as u8)); return Ok(Some(self.maps.len() as u8));

View file

@ -3,12 +3,13 @@ use crate::{
discord::oppai_cache::{Accuracy, BeatmapContent, BeatmapInfo, BeatmapInfoWithPP}, discord::oppai_cache::{Accuracy, BeatmapContent, BeatmapInfo, BeatmapInfoWithPP},
models::{Beatmap, Difficulty, Mode, Mods, Rank, Score, User}, models::{Beatmap, Difficulty, Mode, Mods, Rank, Score, User},
}; };
use serenity::{builder::CreateEmbed, utils::MessageBuilder}; use serenity::{
builder::{CreateEmbed, CreateEmbedAuthor, CreateEmbedFooter},
utils::MessageBuilder,
};
use std::time::Duration; use std::time::Duration;
use youmubot_prelude::*; use youmubot_prelude::*;
type CreateEmbedFn = dyn FnOnce(&mut CreateEmbed) -> &mut CreateEmbed + Send + Sync;
/// Writes a number grouped in groups of 3. /// Writes a number grouped in groups of 3.
pub(crate) fn grouped_number(num: u64) -> String { pub(crate) fn grouped_number(num: u64) -> String {
let s = num.to_string(); let s = num.to_string();
@ -24,7 +25,7 @@ pub(crate) fn grouped_number(num: u64) -> String {
fn beatmap_description(b: &Beatmap) -> String { fn beatmap_description(b: &Beatmap) -> String {
MessageBuilder::new() MessageBuilder::new()
.push_bold_line(b.approval) .push_bold_line(b.approval.to_string())
.push({ .push({
let link = b.download_link(false); let link = b.download_link(false);
format!( format!(
@ -36,9 +37,9 @@ fn beatmap_description(b: &Beatmap) -> String {
}) })
.push_line(format!(" [[Beatmapset]]({})", b.beatmapset_link())) .push_line(format!(" [[Beatmapset]]({})", b.beatmapset_link()))
.push("Language: ") .push("Language: ")
.push_bold(b.language) .push_bold(b.language.to_string())
.push(" | Genre: ") .push(" | Genre: ")
.push_bold_line(b.genre) .push_bold_line(b.genre.to_string())
.push( .push(
b.source b.source
.as_ref() .as_ref()
@ -62,7 +63,7 @@ pub fn beatmap_offline_embed(
b: &'_ crate::discord::oppai_cache::BeatmapContent, b: &'_ crate::discord::oppai_cache::BeatmapContent,
m: Mode, m: Mode,
mods: Mods, mods: Mods,
) -> Result<Box<CreateEmbedFn>> { ) -> Result<CreateEmbed> {
let bm = b.content.clone(); let bm = b.content.clone();
let metadata = b.metadata.clone(); let metadata = b.metadata.clone();
let (info, pp) = b.get_possible_pp_with(m, mods)?; let (info, pp) = b.get_possible_pp_with(m, mods)?;
@ -93,15 +94,16 @@ pub fn beatmap_offline_embed(
total_length, total_length,
} }
.apply_mods(mods, info.stars); .apply_mods(mods, info.stars);
Ok(Box::new(move |c: &mut CreateEmbed| { Ok(
c.title(beatmap_title( CreateEmbed::new()
.title(beatmap_title(
&metadata.artist, &metadata.artist,
&metadata.title, &metadata.title,
&metadata.version, &metadata.version,
mods, mods,
)) ))
.author(|a| { .author({
a.name(&metadata.creator) CreateEmbedAuthor::new(&metadata.creator)
.url(format!("https://osu.ppy.sh/users/{}", metadata.creator)) .url(format!("https://osu.ppy.sh/users/{}", metadata.creator))
}) })
.color(0xffb6c1) .color(0xffb6c1)
@ -113,9 +115,8 @@ pub fn beatmap_offline_embed(
), ),
false, false,
) )
.field("Information", diff.format_info(m, mods, None), false) .field("Information", diff.format_info(m, mods, None), false), // .description(beatmap_description(b))
// .description(beatmap_description(b)) )
}))
} }
// Some helper functions here // Some helper functions here
@ -148,15 +149,15 @@ pub fn beatmap_embed<'a>(
m: Mode, m: Mode,
mods: Mods, mods: Mods,
info: BeatmapInfoWithPP, info: BeatmapInfoWithPP,
c: &'a mut CreateEmbed, ) -> CreateEmbed {
) -> &'a mut CreateEmbed {
let diff = b.difficulty.apply_mods(mods, info.0.stars); let diff = b.difficulty.apply_mods(mods, info.0.stars);
c.title(beatmap_title(&b.artist, &b.title, &b.difficulty_name, mods)) CreateEmbed::new()
.author(|a| { .title(beatmap_title(&b.artist, &b.title, &b.difficulty_name, mods))
a.name(&b.creator) .author(
CreateEmbedAuthor::new(&b.creator)
.url(format!("https://osu.ppy.sh/users/{}", b.creator_id)) .url(format!("https://osu.ppy.sh/users/{}", b.creator_id))
.icon_url(format!("https://a.ppy.sh/{}", b.creator_id)) .icon_url(format!("https://a.ppy.sh/{}", b.creator_id)),
}) )
.url(b.link()) .url(b.link())
.image(b.cover_url()) .image(b.cover_url())
.color(0xffb6c1) .color(0xffb6c1)
@ -177,25 +178,22 @@ pub fn beatmap_embed<'a>(
const MAX_DIFFS: usize = 25 - 4; const MAX_DIFFS: usize = 25 - 4;
pub fn beatmapset_embed<'a>( pub fn beatmapset_embed<'a>(bs: &'_ [Beatmap], m: Option<Mode>) -> CreateEmbed {
bs: &'_ [Beatmap],
m: Option<Mode>,
c: &'a mut CreateEmbed,
) -> &'a mut CreateEmbed {
let too_many_diffs = bs.len() > MAX_DIFFS; let too_many_diffs = bs.len() > MAX_DIFFS;
let b: &Beatmap = &bs[0]; let b: &Beatmap = &bs[0];
c.title( let mut m = CreateEmbed::new()
.title(
MessageBuilder::new() MessageBuilder::new()
.push_bold_safe(&b.artist) .push_bold_safe(&b.artist)
.push(" - ") .push(" - ")
.push_bold_safe(&b.title) .push_bold_safe(&b.title)
.build(), .build(),
) )
.author(|a| { .author(
a.name(&b.creator) CreateEmbedAuthor::new(&b.creator)
.url(format!("https://osu.ppy.sh/users/{}", b.creator_id)) .url(format!("https://osu.ppy.sh/users/{}", b.creator_id))
.icon_url(format!("https://a.ppy.sh/{}", b.creator_id)) .icon_url(format!("https://a.ppy.sh/{}", b.creator_id)),
}) )
.url(format!( .url(format!(
"https://osu.ppy.sh/beatmapsets/{}", "https://osu.ppy.sh/beatmapsets/{}",
b.beatmapset_id, b.beatmapset_id,
@ -206,17 +204,6 @@ pub fn beatmapset_embed<'a>(
)) ))
.color(0xffb6c1) .color(0xffb6c1)
.description(beatmap_description(b)) .description(beatmap_description(b))
.footer(|f| {
if too_many_diffs {
f.text(format!(
"This map has {} diffs, we are showing the last {}.",
bs.len(),
MAX_DIFFS
))
} else {
f
}
})
.fields(bs.iter().rev().take(MAX_DIFFS).rev().map(|b: &Beatmap| { .fields(bs.iter().rev().take(MAX_DIFFS).rev().map(|b: &Beatmap| {
( (
format!("[{}]", b.difficulty_name), format!("[{}]", b.difficulty_name),
@ -224,7 +211,15 @@ pub fn beatmapset_embed<'a>(
.format_info(m.unwrap_or(b.mode), Mods::NOMOD, b), .format_info(m.unwrap_or(b.mode), Mods::NOMOD, b),
false, false,
) )
})) }));
if too_many_diffs {
m = m.footer(CreateEmbedFooter::new(format!(
"This map has {} diffs, we are showing the last {}.",
bs.len(),
MAX_DIFFS
)));
}
m
} }
pub(crate) struct ScoreEmbedBuilder<'a> { pub(crate) struct ScoreEmbedBuilder<'a> {
@ -271,7 +266,7 @@ pub(crate) fn score_embed<'a>(
impl<'a> ScoreEmbedBuilder<'a> { impl<'a> ScoreEmbedBuilder<'a> {
#[allow(clippy::many_single_char_names)] #[allow(clippy::many_single_char_names)]
pub fn build<'b>(&mut self, m: &'b mut CreateEmbed) -> &'b mut CreateEmbed { pub fn build<'b>(&mut self) -> CreateEmbed {
let mode = self.bm.mode(); let mode = self.bm.mode();
let b = &self.bm.0; let b = &self.bm.0;
let s = self.s; let s = self.s;
@ -366,7 +361,12 @@ impl<'a> ScoreEmbedBuilder<'a> {
} else { } else {
format!("by {} ", b.creator) format!("by {} ", b.creator)
}; };
m.author(|f| f.name(&u.username).url(u.link()).icon_url(u.avatar_url())) let mut m = CreateEmbed::new()
.author(
CreateEmbedAuthor::new(&u.username)
.url(u.link())
.icon_url(u.avatar_url()),
)
.color(0xffb6c1) .color(0xffb6c1)
.title( .title(
MessageBuilder::new() MessageBuilder::new()
@ -378,7 +378,7 @@ impl<'a> ScoreEmbedBuilder<'a> {
.push(" [") .push(" [")
.push_safe(&b.difficulty_name) .push_safe(&b.difficulty_name)
.push("] ") .push("] ")
.push(s.mods) .push(s.mods.to_string())
.push(" ") .push(" ")
.push(format!("({:.2}\\*)", stars)) .push(format!("({:.2}\\*)", stars))
.push(" ") .push(" ")
@ -420,7 +420,7 @@ impl<'a> ScoreEmbedBuilder<'a> {
footer += " Star difficulty does not reflect game mods."; footer += " Star difficulty does not reflect game mods.";
} }
if !footer.is_empty() { if !footer.is_empty() {
m.footer(|f| f.text(footer)); m = m.footer(CreateEmbedFooter::new(footer));
} }
m m
} }
@ -429,9 +429,9 @@ impl<'a> ScoreEmbedBuilder<'a> {
pub(crate) fn user_embed( pub(crate) fn user_embed(
u: User, u: User,
best: Option<(Score, BeatmapWithMode, BeatmapInfo)>, best: Option<(Score, BeatmapWithMode, BeatmapInfo)>,
m: &mut CreateEmbed, ) -> CreateEmbed {
) -> &mut CreateEmbed { CreateEmbed::new()
m.title(MessageBuilder::new().push_safe(u.username).build()) .title(MessageBuilder::new().push_safe(u.username).build())
.url(format!("https://osu.ppy.sh/users/{}", u.id)) .url(format!("https://osu.ppy.sh/users/{}", u.id))
.color(0xffb6c1) .color(0xffb6c1)
.thumbnail(format!("https://a.ppy.sh/{}", u.id)) .thumbnail(format!("https://a.ppy.sh/{}", u.id))
@ -494,7 +494,7 @@ pub(crate) fn user_embed(
v.pp.unwrap() /*Top record should have pp*/ v.pp.unwrap() /*Top record should have pp*/
)) ))
.push(" - ") .push(" - ")
.push_line(v.date.format("<t:%s:R>")) .push_line(v.date.format("<t:%s:R>").to_string())
.push("on ") .push("on ")
.push_line(format!( .push_line(format!(
"[{} - {} [{}]]({})**{} **", "[{} - {} [{}]]({})**{} **",

View file

@ -5,7 +5,7 @@ use crate::{
}; };
use lazy_static::lazy_static; use lazy_static::lazy_static;
use regex::Regex; use regex::Regex;
use serenity::{builder::CreateEmbed, model::channel::Message, utils::MessageBuilder}; use serenity::{builder::CreateMessage, model::channel::Message, utils::MessageBuilder};
use std::str::FromStr; use std::str::FromStr;
use youmubot_prelude::*; use youmubot_prelude::*;
@ -46,17 +46,12 @@ pub fn dot_osu_hook<'a>(
let data = ctx.data.read().await; let data = ctx.data.read().await;
let oppai = data.get::<BeatmapCache>().unwrap(); let oppai = data.get::<BeatmapCache>().unwrap();
let (beatmap, _) = oppai.download_beatmap_from_url(&url).await.ok()?; let (beatmap, _) = oppai.download_beatmap_from_url(&url).await.ok()?;
let embed_fn = crate::discord::embeds::beatmap_offline_embed( crate::discord::embeds::beatmap_offline_embed(
&beatmap, &beatmap,
Mode::from(beatmap.content.mode as u8), /*For now*/ Mode::from(beatmap.content.mode as u8), /*For now*/
msg.content.trim().parse().unwrap_or(Mods::NOMOD), msg.content.trim().parse().unwrap_or(Mods::NOMOD),
) )
.ok()?; .pls_ok()
let mut create_embed = CreateEmbed::default();
embed_fn(&mut create_embed);
Some(create_embed)
} }
}) })
.collect::<stream::FuturesUnordered<_>>() .collect::<stream::FuturesUnordered<_>>()
@ -80,16 +75,12 @@ pub fn dot_osu_hook<'a>(
beatmaps beatmaps
.into_iter() .into_iter()
.filter_map(|beatmap| { .filter_map(|beatmap| {
let embed_fn = crate::discord::embeds::beatmap_offline_embed( crate::discord::embeds::beatmap_offline_embed(
&beatmap, &beatmap,
Mode::from(beatmap.content.mode as u8), /*For now*/ Mode::from(beatmap.content.mode as u8), /*For now*/
msg.content.trim().parse().unwrap_or(Mods::NOMOD), msg.content.trim().parse().unwrap_or(Mods::NOMOD),
) )
.pls_ok()?; .pls_ok()
let mut create_embed = CreateEmbed::default();
embed_fn(&mut create_embed);
Some(create_embed)
}) })
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
) )
@ -105,11 +96,13 @@ pub fn dot_osu_hook<'a>(
if !osu_embeds.is_empty() { if !osu_embeds.is_empty() {
msg.channel_id msg.channel_id
.send_message(ctx, |f| { .send_message(
f.reference_message(msg) ctx,
CreateMessage::new()
.reference_message(msg)
.content(format!("{} attached beatmaps found", osu_embeds.len())) .content(format!("{} attached beatmaps found", osu_embeds.len()))
.add_embeds(osu_embeds) .add_embeds(osu_embeds),
}) )
.await .await
.ok(); .ok();
} }
@ -387,16 +380,23 @@ async fn handle_beatmap<'a, 'b>(
) -> Result<()> { ) -> Result<()> {
reply_to reply_to
.channel_id .channel_id
.send_message(ctx, |m| { .send_message(
m.content( ctx,
CreateMessage::new()
.content(
MessageBuilder::new() MessageBuilder::new()
.push("Beatmap information for ") .push("Beatmap information for ")
.push_mono_safe(link) .push_mono_safe(link)
.build(), .build(),
) )
.embed(|b| beatmap_embed(beatmap, mode.unwrap_or(beatmap.mode), mods, info, b)) .embed(beatmap_embed(
.reference_message(reply_to) beatmap,
}) mode.unwrap_or(beatmap.mode),
mods,
info,
))
.reference_message(reply_to),
)
.await?; .await?;
Ok(()) Ok(())
} }

View file

@ -8,7 +8,8 @@ use crate::{
}; };
use rand::seq::IteratorRandom; use rand::seq::IteratorRandom;
use serenity::{ use serenity::{
collector::{CollectReaction, ReactionAction}, builder::{CreateMessage, EditMessage},
collector,
framework::standard::{ framework::standard::{
macros::{command, group}, macros::{command, group},
Args, CommandResult, Args, CommandResult,
@ -237,27 +238,26 @@ pub async fn save(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult
.get_possible_pp_with(mode, Mods::NOMOD)?; .get_possible_pp_with(mode, Mods::NOMOD)?;
let mut reply = reply.await?; let mut reply = reply.await?;
reply reply
.edit(&ctx, |f| { .edit(
f.embed(|e| beatmap_embed(&beatmap, mode, Mods::NOMOD, info, e)) &ctx,
}) EditMessage::new().embed(beatmap_embed(&beatmap, mode, Mods::NOMOD, info)),
)
.await?; .await?;
let reaction = reply.react(&ctx, '👌').await?; let reaction = reply.react(&ctx, '👌').await?;
let completed = loop { let completed = loop {
let emoji = reaction.emoji.clone(); let emoji = reaction.emoji.clone();
let user_reaction = CollectReaction::new(ctx) let user_reaction = collector::ReactionCollector::new(&ctx)
.message_id(reply.id.0) .message_id(reply.id)
.author_id(msg.author.id.0) .author_id(msg.author.id)
.filter(move |r| r.emoji == emoji) .filter(move |r| r.emoji == emoji)
.timeout(std::time::Duration::from_secs(300)) .timeout(std::time::Duration::from_secs(300))
.collect_limit(1) .next()
.await; .await;
if let Some(ur) = user_reaction { if let Some(ur) = user_reaction {
if check(osu, &u, score.beatmap_id).await? { if check(osu, &u, score.beatmap_id).await? {
break true; break true;
} }
if let ReactionAction::Added(ur) = &*ur {
ur.delete(&ctx).await?; ur.delete(&ctx).await?;
}
} else { } else {
break false; break false;
} }
@ -423,13 +423,13 @@ pub async fn recent(ctx: &Context, msg: &Message, mut args: Args) -> CommandResu
let beatmap_mode = BeatmapWithMode(beatmap, mode); let beatmap_mode = BeatmapWithMode(beatmap, mode);
msg.channel_id msg.channel_id
.send_message(&ctx, |m| { .send_message(
m.content("Here is the play that you requested".to_string()) &ctx,
.embed(|m| { CreateMessage::new()
score_embed(&recent_play, &beatmap_mode, &content, &user).build(m) .content("Here is the play that you requested".to_string())
}) .embed(score_embed(&recent_play, &beatmap_mode, &content, &user).build())
.reference_message(msg) .reference_message(msg),
}) )
.await?; .await?;
// Save the beatmap... // Save the beatmap...
@ -549,11 +549,13 @@ pub async fn last(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult
.await? .await?
.get_possible_pp_with(m, mods)?; .get_possible_pp_with(m, mods)?;
msg.channel_id msg.channel_id
.send_message(&ctx, |f| { .send_message(
f.content("Here is the beatmap you requested!") &ctx,
.embed(|c| beatmap_embed(&b, m, mods, info, c)) CreateMessage::new()
.reference_message(msg) .content("Here is the beatmap you requested!")
}) .embed(beatmap_embed(&b, m, mods, info))
.reference_message(msg),
)
.await?; .await?;
} }
None => { None => {
@ -671,16 +673,17 @@ pub async fn top(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult
let beatmap = BeatmapWithMode(beatmap, mode); let beatmap = BeatmapWithMode(beatmap, mode);
msg.channel_id msg.channel_id
.send_message(&ctx, |m| { .send_message(&ctx, {
m.content(format!( CreateMessage::new()
.content(format!(
"{}: here is the play that you requested", "{}: here is the play that you requested",
msg.author msg.author
)) ))
.embed(|m| { .embed(
score_embed(&top_play, &beatmap, &content, &user) score_embed(&top_play, &beatmap, &content, &user)
.top_record(rank) .top_record(rank)
.build(m) .build(),
}) )
}) })
.await?; .await?;
@ -740,13 +743,15 @@ async fn get_user(ctx: &Context, msg: &Message, mut args: Args, mode: Mode) -> C
None => None, None => None,
}; };
msg.channel_id msg.channel_id
.send_message(&ctx, |m| { .send_message(
m.content(format!( &ctx,
CreateMessage::new()
.content(format!(
"{}: here is the user that you requested", "{}: here is the user that you requested",
msg.author msg.author
)) ))
.embed(|m| user_embed(u, best, m)) .embed(user_embed(u, best)),
}) )
.await?; .await?;
} }
None => { None => {

View file

@ -11,6 +11,7 @@ use crate::{
}; };
use serenity::{ use serenity::{
builder::EditMessage,
framework::standard::{macros::command, Args, CommandResult}, framework::standard::{macros::command, Args, CommandResult},
model::channel::Message, model::channel::Message,
utils::MessageBuilder, utils::MessageBuilder,
@ -141,7 +142,8 @@ pub async fn server_rank(ctx: &Context, m: &Message, mut args: Args) -> CommandR
(total_len + ITEMS_PER_PAGE - 1) / ITEMS_PER_PAGE, (total_len + ITEMS_PER_PAGE - 1) / ITEMS_PER_PAGE,
last_update.format("<t:%s:R>"), last_update.format("<t:%s:R>"),
)); ));
m.edit(ctx, |f| f.content(content.to_string())).await?; m.edit(ctx, EditMessage::new().content(content.to_string()))
.await?;
Ok(true) Ok(true)
}) })
}, },
@ -434,7 +436,7 @@ pub async fn show_leaderboard(ctx: &Context, m: &Message, mut args: Args) -> Com
content.push_line("PP was calculated by `oppai-rs`, **not** official values."); content.push_line("PP was calculated by `oppai-rs`, **not** official values.");
} }
m.edit(&ctx, |f| f.content(content.build())).await?; m.edit(&ctx, EditMessage::new().content(content.build())).await?;
Ok(true) Ok(true)
}) })
}, },