mirror of
https://github.com/natsukagami/youmubot.git
synced 2025-04-16 07:18:54 +00:00
Hooks and last works
This commit is contained in:
parent
f8cbd7ceb0
commit
c43f9067b8
5 changed files with 135 additions and 34 deletions
|
@ -1,5 +1,8 @@
|
||||||
use super::BeatmapWithMode;
|
use super::BeatmapWithMode;
|
||||||
use crate::models::{Beatmap, Mode, Rank, Score, User};
|
use crate::{
|
||||||
|
discord::oppai_cache::BeatmapInfo,
|
||||||
|
models::{Beatmap, Mode, Mods, Rank, Score, User},
|
||||||
|
};
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use serenity::{builder::CreateEmbed, utils::MessageBuilder};
|
use serenity::{builder::CreateEmbed, utils::MessageBuilder};
|
||||||
use youmubot_prelude::*;
|
use youmubot_prelude::*;
|
||||||
|
@ -12,7 +15,32 @@ fn format_mode(actual: Mode, original: Mode) -> String {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn beatmap_embed<'a>(b: &'_ Beatmap, m: Mode, c: &'a mut CreateEmbed) -> &'a mut CreateEmbed {
|
pub fn beatmap_embed<'a>(
|
||||||
|
b: &'_ Beatmap,
|
||||||
|
m: Mode,
|
||||||
|
mods: Mods,
|
||||||
|
info: Option<BeatmapInfo>,
|
||||||
|
c: &'a mut CreateEmbed,
|
||||||
|
) -> &'a mut CreateEmbed {
|
||||||
|
let mod_str = if mods == Mods::NOMOD {
|
||||||
|
"".to_owned()
|
||||||
|
} else {
|
||||||
|
format!(" {}", mods)
|
||||||
|
};
|
||||||
|
let total_length = if mods.intersects(Mods::DT | Mods::NC) {
|
||||||
|
b.total_length * 2 / 3
|
||||||
|
} else if mods.intersects(Mods::HT) {
|
||||||
|
b.total_length * 4 / 3
|
||||||
|
} else {
|
||||||
|
b.total_length
|
||||||
|
};
|
||||||
|
let drain_length = if mods.intersects(Mods::DT | Mods::NC) {
|
||||||
|
b.drain_length * 2 / 3
|
||||||
|
} else if mods.intersects(Mods::HT) {
|
||||||
|
b.drain_length * 4 / 3
|
||||||
|
} else {
|
||||||
|
b.drain_length
|
||||||
|
};
|
||||||
c.title(
|
c.title(
|
||||||
MessageBuilder::new()
|
MessageBuilder::new()
|
||||||
.push_bold_safe(&b.artist)
|
.push_bold_safe(&b.artist)
|
||||||
|
@ -21,6 +49,7 @@ pub fn beatmap_embed<'a>(b: &'_ Beatmap, m: Mode, c: &'a mut CreateEmbed) -> &'a
|
||||||
.push(" [")
|
.push(" [")
|
||||||
.push_bold_safe(&b.difficulty_name)
|
.push_bold_safe(&b.difficulty_name)
|
||||||
.push("]")
|
.push("]")
|
||||||
|
.push(&mod_str)
|
||||||
.build(),
|
.build(),
|
||||||
)
|
)
|
||||||
.author(|a| {
|
.author(|a| {
|
||||||
|
@ -34,15 +63,29 @@ pub fn beatmap_embed<'a>(b: &'_ Beatmap, m: Mode, c: &'a mut CreateEmbed) -> &'a
|
||||||
.color(0xffb6c1)
|
.color(0xffb6c1)
|
||||||
.field(
|
.field(
|
||||||
"Star Difficulty",
|
"Star Difficulty",
|
||||||
format!("{:.2}⭐", b.difficulty.stars),
|
format!(
|
||||||
|
"{:.2}⭐",
|
||||||
|
info.map(|v| v.stars as f64).unwrap_or(b.difficulty.stars)
|
||||||
|
),
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
|
.fields(info.map(|info| {
|
||||||
|
(
|
||||||
|
"Calculated pp",
|
||||||
|
format!(
|
||||||
|
"95%: **{:.2}**pp, 98%: **{:.2}**pp, 99%: **{:.2}**pp, 100%: **{:.2}**pp",
|
||||||
|
info.pp[0], info.pp[1], info.pp[2], info.pp[3]
|
||||||
|
),
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
.fields(Some(("Mods", mods, false)).filter(|_| mods != Mods::NOMOD))
|
||||||
.field(
|
.field(
|
||||||
"Length",
|
"Length",
|
||||||
MessageBuilder::new()
|
MessageBuilder::new()
|
||||||
.push_bold_safe(Duration(b.total_length))
|
.push_bold_safe(Duration(total_length))
|
||||||
.push(" (")
|
.push(" (")
|
||||||
.push_bold_safe(Duration(b.drain_length))
|
.push_bold_safe(Duration(drain_length))
|
||||||
.push(" drain)")
|
.push(" drain)")
|
||||||
.build(),
|
.build(),
|
||||||
false,
|
false,
|
||||||
|
@ -90,6 +133,12 @@ pub fn beatmap_embed<'a>(b: &'_ Beatmap, m: Mode, c: &'a mut CreateEmbed) -> &'a
|
||||||
.push_bold(&b.genre)
|
.push_bold(&b.genre)
|
||||||
.build(),
|
.build(),
|
||||||
)
|
)
|
||||||
|
.footer(|f| {
|
||||||
|
if info.is_none() && mods != Mods::NOMOD {
|
||||||
|
f.text("Star difficulty not reflecting mods applied.");
|
||||||
|
}
|
||||||
|
f
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const MAX_DIFFS: usize = 25 - 4;
|
const MAX_DIFFS: usize = 25 - 4;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use super::OsuClient;
|
use super::OsuClient;
|
||||||
use crate::{
|
use crate::{
|
||||||
models::{Beatmap, Mode},
|
discord::oppai_cache::{BeatmapCache, BeatmapInfo},
|
||||||
|
models::{Beatmap, Mode, Mods},
|
||||||
request::BeatmapRequestKind,
|
request::BeatmapRequestKind,
|
||||||
};
|
};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
@ -11,6 +12,7 @@ use serenity::{
|
||||||
model::channel::Message,
|
model::channel::Message,
|
||||||
utils::MessageBuilder,
|
utils::MessageBuilder,
|
||||||
};
|
};
|
||||||
|
use std::str::FromStr;
|
||||||
use youmubot_prelude::*;
|
use youmubot_prelude::*;
|
||||||
|
|
||||||
use super::embeds::{beatmap_embed, beatmapset_embed};
|
use super::embeds::{beatmap_embed, beatmapset_embed};
|
||||||
|
@ -34,13 +36,13 @@ pub fn hook(ctx: &mut Context, msg: &Message) -> () {
|
||||||
let mut last_beatmap = None;
|
let mut last_beatmap = None;
|
||||||
for l in old_links.into_iter().chain(new_links.into_iter()) {
|
for l in old_links.into_iter().chain(new_links.into_iter()) {
|
||||||
if let Err(v) = msg.channel_id.send_message(&ctx, |m| match l.embed {
|
if let Err(v) = msg.channel_id.send_message(&ctx, |m| match l.embed {
|
||||||
EmbedType::Beatmap(b) => {
|
EmbedType::Beatmap(b, info, mods) => {
|
||||||
let t = handle_beatmap(&b, l.link, l.mode, l.mods, m);
|
let t = handle_beatmap(&b, info, l.link, l.mode, mods, m);
|
||||||
let mode = l.mode.unwrap_or(b.mode);
|
let mode = l.mode.unwrap_or(b.mode);
|
||||||
last_beatmap = Some(super::BeatmapWithMode(b, mode));
|
last_beatmap = Some(super::BeatmapWithMode(b, mode));
|
||||||
t
|
t
|
||||||
}
|
}
|
||||||
EmbedType::Beatmapset(b) => handle_beatmapset(b, l.link, l.mode, l.mods, m),
|
EmbedType::Beatmapset(b) => handle_beatmapset(b, l.link, l.mode, m),
|
||||||
}) {
|
}) {
|
||||||
println!("Error in osu! hook: {:?}", v)
|
println!("Error in osu! hook: {:?}", v)
|
||||||
}
|
}
|
||||||
|
@ -59,7 +61,7 @@ pub fn hook(ctx: &mut Context, msg: &Message) -> () {
|
||||||
}
|
}
|
||||||
|
|
||||||
enum EmbedType {
|
enum EmbedType {
|
||||||
Beatmap(Beatmap),
|
Beatmap(Beatmap, Option<BeatmapInfo>, Mods),
|
||||||
Beatmapset(Vec<Beatmap>),
|
Beatmapset(Vec<Beatmap>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,12 +69,12 @@ struct ToPrint<'a> {
|
||||||
embed: EmbedType,
|
embed: EmbedType,
|
||||||
link: &'a str,
|
link: &'a str,
|
||||||
mode: Option<Mode>,
|
mode: Option<Mode>,
|
||||||
mods: Option<&'a str>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_old_links<'a>(ctx: &mut Context, content: &'a str) -> Result<Vec<ToPrint<'a>>, Error> {
|
fn handle_old_links<'a>(ctx: &mut Context, content: &'a str) -> Result<Vec<ToPrint<'a>>, Error> {
|
||||||
let osu = ctx.data.get_cloned::<OsuClient>();
|
let osu = ctx.data.get_cloned::<OsuClient>();
|
||||||
let mut to_prints: Vec<ToPrint<'a>> = Vec::new();
|
let mut to_prints: Vec<ToPrint<'a>> = Vec::new();
|
||||||
|
let cache = ctx.data.get_cloned::<BeatmapCache>();
|
||||||
for capture in OLD_LINK_REGEX.captures_iter(content) {
|
for capture in OLD_LINK_REGEX.captures_iter(content) {
|
||||||
let req_type = capture.name("link_type").unwrap().as_str();
|
let req_type = capture.name("link_type").unwrap().as_str();
|
||||||
let req = match req_type {
|
let req = match req_type {
|
||||||
|
@ -100,11 +102,22 @@ fn handle_old_links<'a>(ctx: &mut Context, content: &'a str) -> Result<Vec<ToPri
|
||||||
match req_type {
|
match req_type {
|
||||||
"b" => {
|
"b" => {
|
||||||
for b in beatmaps.into_iter() {
|
for b in beatmaps.into_iter() {
|
||||||
|
// collect beatmap info
|
||||||
|
let mods = capture
|
||||||
|
.name("mods")
|
||||||
|
.map(|v| Mods::from_str(v.as_str()).ok())
|
||||||
|
.flatten()
|
||||||
|
.unwrap_or(Mods::NOMOD);
|
||||||
|
let info = mode.unwrap_or(b.mode).to_oppai_mode().and_then(|mode| {
|
||||||
|
cache
|
||||||
|
.get_beatmap(b.beatmap_id)
|
||||||
|
.and_then(|b| b.get_info_with(Some(mode), mods))
|
||||||
|
.ok()
|
||||||
|
});
|
||||||
to_prints.push(ToPrint {
|
to_prints.push(ToPrint {
|
||||||
embed: EmbedType::Beatmap(b),
|
embed: EmbedType::Beatmap(b, info, mods),
|
||||||
link: capture.get(0).unwrap().as_str(),
|
link: capture.get(0).unwrap().as_str(),
|
||||||
mode,
|
mode,
|
||||||
mods: capture.name("mods").map(|v| v.as_str()),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,7 +125,6 @@ fn handle_old_links<'a>(ctx: &mut Context, content: &'a str) -> Result<Vec<ToPri
|
||||||
embed: EmbedType::Beatmapset(beatmaps),
|
embed: EmbedType::Beatmapset(beatmaps),
|
||||||
link: capture.get(0).unwrap().as_str(),
|
link: capture.get(0).unwrap().as_str(),
|
||||||
mode,
|
mode,
|
||||||
mods: capture.name("mods").map(|v| v.as_str()),
|
|
||||||
}),
|
}),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
@ -123,6 +135,7 @@ fn handle_old_links<'a>(ctx: &mut Context, content: &'a str) -> Result<Vec<ToPri
|
||||||
fn handle_new_links<'a>(ctx: &mut Context, content: &'a str) -> Result<Vec<ToPrint<'a>>, Error> {
|
fn handle_new_links<'a>(ctx: &mut Context, content: &'a str) -> Result<Vec<ToPrint<'a>>, Error> {
|
||||||
let osu = ctx.data.get_cloned::<OsuClient>();
|
let osu = ctx.data.get_cloned::<OsuClient>();
|
||||||
let mut to_prints: Vec<ToPrint<'a>> = Vec::new();
|
let mut to_prints: Vec<ToPrint<'a>> = Vec::new();
|
||||||
|
let cache = ctx.data.get_cloned::<BeatmapCache>();
|
||||||
for capture in NEW_LINK_REGEX.captures_iter(content) {
|
for capture in NEW_LINK_REGEX.captures_iter(content) {
|
||||||
let mode = capture.name("mode").and_then(|v| {
|
let mode = capture.name("mode").and_then(|v| {
|
||||||
Some(match v.as_str() {
|
Some(match v.as_str() {
|
||||||
|
@ -133,7 +146,6 @@ fn handle_new_links<'a>(ctx: &mut Context, content: &'a str) -> Result<Vec<ToPri
|
||||||
_ => return None,
|
_ => return None,
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
let mods = capture.name("mods").map(|v| v.as_str());
|
|
||||||
let link = capture.get(0).unwrap().as_str();
|
let link = capture.get(0).unwrap().as_str();
|
||||||
let req = match capture.name("beatmap_id") {
|
let req = match capture.name("beatmap_id") {
|
||||||
Some(ref v) => BeatmapRequestKind::Beatmap(v.as_str().parse()?),
|
Some(ref v) => BeatmapRequestKind::Beatmap(v.as_str().parse()?),
|
||||||
|
@ -148,10 +160,24 @@ fn handle_new_links<'a>(ctx: &mut Context, content: &'a str) -> Result<Vec<ToPri
|
||||||
match capture.name("beatmap_id") {
|
match capture.name("beatmap_id") {
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
for beatmap in beatmaps.into_iter() {
|
for beatmap in beatmaps.into_iter() {
|
||||||
|
// collect beatmap info
|
||||||
|
let mods = capture
|
||||||
|
.name("mods")
|
||||||
|
.map(|v| Mods::from_str(v.as_str()).ok())
|
||||||
|
.flatten()
|
||||||
|
.unwrap_or(Mods::NOMOD);
|
||||||
|
let info = mode
|
||||||
|
.unwrap_or(beatmap.mode)
|
||||||
|
.to_oppai_mode()
|
||||||
|
.and_then(|mode| {
|
||||||
|
cache
|
||||||
|
.get_beatmap(beatmap.beatmap_id)
|
||||||
|
.and_then(|b| b.get_info_with(Some(mode), mods))
|
||||||
|
.ok()
|
||||||
|
});
|
||||||
to_prints.push(ToPrint {
|
to_prints.push(ToPrint {
|
||||||
embed: EmbedType::Beatmap(beatmap),
|
embed: EmbedType::Beatmap(beatmap, info, mods),
|
||||||
link,
|
link,
|
||||||
mods,
|
|
||||||
mode,
|
mode,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -159,7 +185,6 @@ fn handle_new_links<'a>(ctx: &mut Context, content: &'a str) -> Result<Vec<ToPri
|
||||||
None => to_prints.push(ToPrint {
|
None => to_prints.push(ToPrint {
|
||||||
embed: EmbedType::Beatmapset(beatmaps),
|
embed: EmbedType::Beatmapset(beatmaps),
|
||||||
link,
|
link,
|
||||||
mods,
|
|
||||||
mode,
|
mode,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
@ -169,9 +194,10 @@ fn handle_new_links<'a>(ctx: &mut Context, content: &'a str) -> Result<Vec<ToPri
|
||||||
|
|
||||||
fn handle_beatmap<'a, 'b>(
|
fn handle_beatmap<'a, 'b>(
|
||||||
beatmap: &Beatmap,
|
beatmap: &Beatmap,
|
||||||
|
info: Option<BeatmapInfo>,
|
||||||
link: &'_ str,
|
link: &'_ str,
|
||||||
mode: Option<Mode>,
|
mode: Option<Mode>,
|
||||||
mods: Option<&'_ str>,
|
mods: Mods,
|
||||||
m: &'a mut CreateMessage<'b>,
|
m: &'a mut CreateMessage<'b>,
|
||||||
) -> &'a mut CreateMessage<'b> {
|
) -> &'a mut CreateMessage<'b> {
|
||||||
m.content(
|
m.content(
|
||||||
|
@ -180,14 +206,13 @@ fn handle_beatmap<'a, 'b>(
|
||||||
.push_mono_safe(link)
|
.push_mono_safe(link)
|
||||||
.build(),
|
.build(),
|
||||||
)
|
)
|
||||||
.embed(|b| beatmap_embed(beatmap, mode.unwrap_or(beatmap.mode), b))
|
.embed(|b| beatmap_embed(beatmap, mode.unwrap_or(beatmap.mode), mods, info, b))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_beatmapset<'a, 'b>(
|
fn handle_beatmapset<'a, 'b>(
|
||||||
beatmaps: Vec<Beatmap>,
|
beatmaps: Vec<Beatmap>,
|
||||||
link: &'_ str,
|
link: &'_ str,
|
||||||
mode: Option<Mode>,
|
mode: Option<Mode>,
|
||||||
mods: Option<&'_ str>,
|
|
||||||
m: &'a mut CreateMessage<'b>,
|
m: &'a mut CreateMessage<'b>,
|
||||||
) -> &'a mut CreateMessage<'b> {
|
) -> &'a mut CreateMessage<'b> {
|
||||||
let mut beatmaps = beatmaps;
|
let mut beatmaps = beatmaps;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
models::{Beatmap, Mode, Score, User},
|
discord::oppai_cache::BeatmapCache,
|
||||||
|
models::{Beatmap, Mode, Mods, Score, User},
|
||||||
request::{BeatmapRequestKind, UserID},
|
request::{BeatmapRequestKind, UserID},
|
||||||
Client as OsuHttpClient,
|
Client as OsuHttpClient,
|
||||||
};
|
};
|
||||||
|
@ -20,7 +21,7 @@ mod cache;
|
||||||
mod db;
|
mod db;
|
||||||
pub(crate) mod embeds;
|
pub(crate) mod embeds;
|
||||||
mod hook;
|
mod hook;
|
||||||
mod oppai_cache;
|
pub(crate) mod oppai_cache;
|
||||||
mod server_rank;
|
mod server_rank;
|
||||||
|
|
||||||
use db::OsuUser;
|
use db::OsuUser;
|
||||||
|
@ -334,18 +335,26 @@ pub fn recent(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResult
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
#[description = "Show information from the last queried beatmap."]
|
#[description = "Show information from the last queried beatmap."]
|
||||||
#[num_args(0)]
|
#[usage = "[mods = no mod]"]
|
||||||
pub fn last(ctx: &mut Context, msg: &Message, _: Args) -> CommandResult {
|
#[max_args(1)]
|
||||||
|
pub fn last(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResult {
|
||||||
let b = cache::get_beatmap(&*ctx.data.read(), msg.channel_id)?;
|
let b = cache::get_beatmap(&*ctx.data.read(), msg.channel_id)?;
|
||||||
|
|
||||||
match b {
|
match b {
|
||||||
Some(BeatmapWithMode(b, m)) => {
|
Some(BeatmapWithMode(b, m)) => {
|
||||||
|
let mods = args.find::<Mods>().unwrap_or(Mods::NOMOD);
|
||||||
|
let info = ctx
|
||||||
|
.data
|
||||||
|
.get_cloned::<BeatmapCache>()
|
||||||
|
.get_beatmap(b.beatmap_id)?
|
||||||
|
.get_info_with(m.to_oppai_mode(), mods)
|
||||||
|
.ok();
|
||||||
msg.channel_id.send_message(&ctx, |f| {
|
msg.channel_id.send_message(&ctx, |f| {
|
||||||
f.content(format!(
|
f.content(format!(
|
||||||
"{}: here is the beatmap you requested!",
|
"{}: here is the beatmap you requested!",
|
||||||
msg.author
|
msg.author
|
||||||
))
|
))
|
||||||
.embed(|c| beatmap_embed(&b, m, c))
|
.embed(|c| beatmap_embed(&b, m, mods, info, c))
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
|
|
@ -12,8 +12,8 @@ pub struct BeatmapContent {
|
||||||
/// the output of "one" oppai run.
|
/// the output of "one" oppai run.
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct BeatmapInfo {
|
pub struct BeatmapInfo {
|
||||||
stars: f32,
|
pub stars: f32,
|
||||||
pp: [f32; 4], // 95, 98, 99, 100
|
pub pp: [f32; 4], // 95, 98, 99, 100
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BeatmapContent {
|
impl BeatmapContent {
|
||||||
|
@ -22,21 +22,27 @@ impl BeatmapContent {
|
||||||
&self,
|
&self,
|
||||||
combo: oppai_rs::Combo,
|
combo: oppai_rs::Combo,
|
||||||
accuracy: f32,
|
accuracy: f32,
|
||||||
|
mode: Option<oppai_rs::Mode>,
|
||||||
mods: impl Into<oppai_rs::Mods>,
|
mods: impl Into<oppai_rs::Mods>,
|
||||||
) -> Result<f32, CommandError> {
|
) -> Result<f32, CommandError> {
|
||||||
Ok(oppai_rs::Oppai::new_from_content(&self.content[..])?
|
let mut oppai = oppai_rs::Oppai::new_from_content(&self.content[..])?;
|
||||||
.combo(combo)?
|
oppai.combo(combo)?.accuracy(accuracy)?.mods(mods.into());
|
||||||
.accuracy(accuracy)?
|
if let Some(mode) = mode {
|
||||||
.mods(mods.into())
|
oppai.mode(mode)?;
|
||||||
.pp())
|
}
|
||||||
|
Ok(oppai.pp())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get info given mods.
|
/// Get info given mods.
|
||||||
pub fn get_info_with(
|
pub fn get_info_with(
|
||||||
&self,
|
&self,
|
||||||
|
mode: Option<oppai_rs::Mode>,
|
||||||
mods: impl Into<oppai_rs::Mods>,
|
mods: impl Into<oppai_rs::Mods>,
|
||||||
) -> Result<BeatmapInfo, CommandError> {
|
) -> Result<BeatmapInfo, CommandError> {
|
||||||
let mut oppai = oppai_rs::Oppai::new_from_content(&self.content[..])?;
|
let mut oppai = oppai_rs::Oppai::new_from_content(&self.content[..])?;
|
||||||
|
if let Some(mode) = mode {
|
||||||
|
oppai.mode(mode)?;
|
||||||
|
}
|
||||||
oppai.mods(mods.into()).combo(oppai_rs::Combo::PERFECT)?;
|
oppai.mods(mods.into()).combo(oppai_rs::Combo::PERFECT)?;
|
||||||
let pp = [
|
let pp = [
|
||||||
oppai.accuracy(95.0)?.pp(),
|
oppai.accuracy(95.0)?.pp(),
|
||||||
|
@ -50,6 +56,7 @@ impl BeatmapContent {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A central cache for the beatmaps.
|
/// A central cache for the beatmaps.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub struct BeatmapCache {
|
pub struct BeatmapCache {
|
||||||
client: reqwest::blocking::Client,
|
client: reqwest::blocking::Client,
|
||||||
cache: Arc<dashmap::DashMap<u64, BeatmapContent>>,
|
cache: Arc<dashmap::DashMap<u64, BeatmapContent>>,
|
||||||
|
@ -67,7 +74,7 @@ impl BeatmapCache {
|
||||||
fn download_beatmap(&self, id: u64) -> Result<BeatmapContent, CommandError> {
|
fn download_beatmap(&self, id: u64) -> Result<BeatmapContent, CommandError> {
|
||||||
let content = self
|
let content = self
|
||||||
.client
|
.client
|
||||||
.get(&format!("https://osu.ppy.sh/u/{}", id))
|
.get(&format!("https://osu.ppy.sh/osu/{}", id))
|
||||||
.send()?
|
.send()?
|
||||||
.bytes()?;
|
.bytes()?;
|
||||||
Ok(BeatmapContent {
|
Ok(BeatmapContent {
|
||||||
|
|
|
@ -118,6 +118,17 @@ impl fmt::Display for Mode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Mode {
|
||||||
|
/// Convert to oppai mode.
|
||||||
|
pub fn to_oppai_mode(self) -> Option<oppai_rs::Mode> {
|
||||||
|
Some(match self {
|
||||||
|
Mode::Std => oppai_rs::Mode::Std,
|
||||||
|
Mode::Taiko => oppai_rs::Mode::Taiko,
|
||||||
|
_ => return None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct Beatmap {
|
pub struct Beatmap {
|
||||||
// Beatmapset info
|
// Beatmapset info
|
||||||
|
|
Loading…
Add table
Reference in a new issue