mirror of
https://github.com/natsukagami/youmubot.git
synced 2025-04-19 08:48:54 +00:00
Update youmubot-osu
This commit is contained in:
parent
2db59905b2
commit
0460e800e5
7 changed files with 229 additions and 218 deletions
|
@ -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,31 +292,33 @@ 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(),
|
||||||
ScoreType::TopRecord(_) => {
|
CreateMessage::new()
|
||||||
format!("New top record from {}!", self.discord_user.mention())
|
.content(match self.kind {
|
||||||
}
|
ScoreType::TopRecord(_) => {
|
||||||
ScoreType::WorldRecord(rank) => {
|
format!("New top record from {}!", self.discord_user.mention())
|
||||||
if rank <= 100 {
|
|
||||||
format!(
|
|
||||||
"New leaderboard record from {}!",
|
|
||||||
self.discord_user.mention()
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
format!("New leaderboard record from **{}**!", member.distinct())
|
|
||||||
}
|
}
|
||||||
}
|
ScoreType::WorldRecord(rank) => {
|
||||||
})
|
if rank <= 100 {
|
||||||
.embed(|e| {
|
format!(
|
||||||
let mut b = score_embed(&self.score, bm, content, self.user);
|
"New leaderboard record from {}!",
|
||||||
match self.kind {
|
self.discord_user.mention()
|
||||||
ScoreType::TopRecord(rank) => b.top_record(rank),
|
)
|
||||||
ScoreType::WorldRecord(rank) => b.world_record(rank),
|
} else {
|
||||||
}
|
format!("New leaderboard record from **{}**!", member.distinct())
|
||||||
.build(e)
|
}
|
||||||
})
|
}
|
||||||
})
|
})
|
||||||
|
.embed({
|
||||||
|
let mut b = score_embed(&self.score, bm, content, self.user);
|
||||||
|
match self.kind {
|
||||||
|
ScoreType::TopRecord(rank) => b.top_record(rank),
|
||||||
|
ScoreType::WorldRecord(rank) => b.world_record(rank),
|
||||||
|
}
|
||||||
|
.build()
|
||||||
|
}),
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
save_beatmap(&*ctx.data.read().await, channel, bm)
|
save_beatmap(&*ctx.data.read().await, channel, bm)
|
||||||
.await
|
.await
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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,29 +94,29 @@ 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()
|
||||||
&metadata.artist,
|
.title(beatmap_title(
|
||||||
&metadata.title,
|
&metadata.artist,
|
||||||
&metadata.version,
|
&metadata.title,
|
||||||
mods,
|
&metadata.version,
|
||||||
))
|
mods,
|
||||||
.author(|a| {
|
))
|
||||||
a.name(&metadata.creator)
|
.author({
|
||||||
.url(format!("https://osu.ppy.sh/users/{}", metadata.creator))
|
CreateEmbedAuthor::new(&metadata.creator)
|
||||||
})
|
.url(format!("https://osu.ppy.sh/users/{}", metadata.creator))
|
||||||
.color(0xffb6c1)
|
})
|
||||||
.field(
|
.color(0xffb6c1)
|
||||||
"Calculated pp",
|
.field(
|
||||||
format!(
|
"Calculated pp",
|
||||||
"95%: **{:.2}**pp, 98%: **{:.2}**pp, 99%: **{:.2}**pp, 100%: **{:.2}**pp",
|
format!(
|
||||||
pp[0], pp[1], pp[2], pp[3]
|
"95%: **{:.2}**pp, 98%: **{:.2}**pp, 99%: **{:.2}**pp, 100%: **{:.2}**pp",
|
||||||
),
|
pp[0], pp[1], pp[2], pp[3]
|
||||||
false,
|
),
|
||||||
)
|
false,
|
||||||
.field("Information", diff.format_info(m, mods, None), false)
|
)
|
||||||
// .description(beatmap_description(b))
|
.field("Information", diff.format_info(m, mods, None), false), // .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,54 +178,48 @@ 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()
|
||||||
MessageBuilder::new()
|
.title(
|
||||||
.push_bold_safe(&b.artist)
|
MessageBuilder::new()
|
||||||
.push(" - ")
|
.push_bold_safe(&b.artist)
|
||||||
.push_bold_safe(&b.title)
|
.push(" - ")
|
||||||
.build(),
|
.push_bold_safe(&b.title)
|
||||||
)
|
.build(),
|
||||||
.author(|a| {
|
|
||||||
a.name(&b.creator)
|
|
||||||
.url(format!("https://osu.ppy.sh/users/{}", b.creator_id))
|
|
||||||
.icon_url(format!("https://a.ppy.sh/{}", b.creator_id))
|
|
||||||
})
|
|
||||||
.url(format!(
|
|
||||||
"https://osu.ppy.sh/beatmapsets/{}",
|
|
||||||
b.beatmapset_id,
|
|
||||||
))
|
|
||||||
.image(format!(
|
|
||||||
"https://assets.ppy.sh/beatmaps/{}/covers/cover.jpg",
|
|
||||||
b.beatmapset_id
|
|
||||||
))
|
|
||||||
.color(0xffb6c1)
|
|
||||||
.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| {
|
|
||||||
(
|
|
||||||
format!("[{}]", b.difficulty_name),
|
|
||||||
b.difficulty
|
|
||||||
.format_info(m.unwrap_or(b.mode), Mods::NOMOD, b),
|
|
||||||
false,
|
|
||||||
)
|
)
|
||||||
}))
|
.author(
|
||||||
|
CreateEmbedAuthor::new(&b.creator)
|
||||||
|
.url(format!("https://osu.ppy.sh/users/{}", b.creator_id))
|
||||||
|
.icon_url(format!("https://a.ppy.sh/{}", b.creator_id)),
|
||||||
|
)
|
||||||
|
.url(format!(
|
||||||
|
"https://osu.ppy.sh/beatmapsets/{}",
|
||||||
|
b.beatmapset_id,
|
||||||
|
))
|
||||||
|
.image(format!(
|
||||||
|
"https://assets.ppy.sh/beatmaps/{}/covers/cover.jpg",
|
||||||
|
b.beatmapset_id
|
||||||
|
))
|
||||||
|
.color(0xffb6c1)
|
||||||
|
.description(beatmap_description(b))
|
||||||
|
.fields(bs.iter().rev().take(MAX_DIFFS).rev().map(|b: &Beatmap| {
|
||||||
|
(
|
||||||
|
format!("[{}]", b.difficulty_name),
|
||||||
|
b.difficulty
|
||||||
|
.format_info(m.unwrap_or(b.mode), Mods::NOMOD, b),
|
||||||
|
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!(
|
||||||
"[{} - {} [{}]]({})**{} **",
|
"[{} - {} [{}]]({})**{} **",
|
||||||
|
|
|
@ -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,
|
||||||
MessageBuilder::new()
|
CreateMessage::new()
|
||||||
.push("Beatmap information for ")
|
.content(
|
||||||
.push_mono_safe(link)
|
MessageBuilder::new()
|
||||||
.build(),
|
.push("Beatmap information for ")
|
||||||
)
|
.push_mono_safe(link)
|
||||||
.embed(|b| beatmap_embed(beatmap, mode.unwrap_or(beatmap.mode), mods, info, b))
|
.build(),
|
||||||
.reference_message(reply_to)
|
)
|
||||||
})
|
.embed(beatmap_embed(
|
||||||
|
beatmap,
|
||||||
|
mode.unwrap_or(beatmap.mode),
|
||||||
|
mods,
|
||||||
|
info,
|
||||||
|
))
|
||||||
|
.reference_message(reply_to),
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
"{}: here is the play that you requested",
|
.content(format!(
|
||||||
msg.author
|
"{}: here is the play that you requested",
|
||||||
))
|
msg.author
|
||||||
.embed(|m| {
|
))
|
||||||
score_embed(&top_play, &beatmap, &content, &user)
|
.embed(
|
||||||
.top_record(rank)
|
score_embed(&top_play, &beatmap, &content, &user)
|
||||||
.build(m)
|
.top_record(rank)
|
||||||
})
|
.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,
|
||||||
"{}: here is the user that you requested",
|
CreateMessage::new()
|
||||||
msg.author
|
.content(format!(
|
||||||
))
|
"{}: here is the user that you requested",
|
||||||
.embed(|m| user_embed(u, best, m))
|
msg.author
|
||||||
})
|
))
|
||||||
|
.embed(user_embed(u, best)),
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
|
|
@ -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)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
Loading…
Add table
Reference in a new issue