osu: add /s/{id} links to the link parser, support beatmapsets with mode override

This commit is contained in:
Natsu Kagami 2025-02-20 14:16:56 +01:00 committed by Natsu Kagami
parent c28cad0718
commit 84b152adf6
5 changed files with 40 additions and 15 deletions

View file

@ -100,7 +100,7 @@ impl BeatmapMetaCache {
} }
/// Get a beatmapset from its ID. /// Get a beatmapset from its ID.
pub async fn get_beatmapset(&self, id: u64) -> Result<Vec<Beatmap>> { pub async fn get_beatmapset(&self, id: u64, mode: Option<Mode>) -> Result<Vec<Beatmap>> {
let bms = models::CachedBeatmap::by_beatmapset(id as i64, &self.pool).await?; let bms = models::CachedBeatmap::by_beatmapset(id as i64, &self.pool).await?;
if !bms.is_empty() { if !bms.is_empty() {
return Ok(bms return Ok(bms
@ -110,7 +110,9 @@ impl BeatmapMetaCache {
} }
let mut beatmaps = self let mut beatmaps = self
.client .client
.beatmaps(crate::BeatmapRequestKind::Beatmapset(id), |f| f) .beatmaps(crate::BeatmapRequestKind::Beatmapset(id), |f| {
f.maybe_mode(mode)
})
.await?; .await?;
if beatmaps.is_empty() { if beatmaps.is_empty() {
return Err(Error::msg("beatmapset not found")); return Err(Error::msg("beatmapset not found"));

View file

@ -709,7 +709,10 @@ async fn parse_map_input(
let output = if beatmapset == Some(true) { let output = if beatmapset == Some(true) {
match output { match output {
EmbedType::Beatmap(beatmap, _, _) => { EmbedType::Beatmap(beatmap, _, _) => {
let beatmaps = env.beatmaps.get_beatmapset(beatmap.beatmapset_id).await?; let beatmaps = env
.beatmaps
.get_beatmapset(beatmap.beatmapset_id, mode)
.await?;
EmbedType::Beatmapset(beatmaps) EmbedType::Beatmapset(beatmaps)
} }
bm @ EmbedType::Beatmapset(_) => bm, bm @ EmbedType::Beatmapset(_) => bm,

View file

@ -313,12 +313,15 @@ async fn handle_last_req(
let mods = mods_def.unwrap_or_default(); let mods = mods_def.unwrap_or_default();
if is_beatmapset_req { if is_beatmapset_req {
let beatmapset = env.beatmaps.get_beatmapset(bm.0.beatmapset_id).await?; let beatmapset = env
.beatmaps
.get_beatmapset(bm.0.beatmapset_id, None)
.await?;
let reply = comp let reply = comp
.create_followup( .create_followup(
&ctx, &ctx,
CreateInteractionResponseFollowup::new() CreateInteractionResponseFollowup::new()
.content(format!("Beatmapset of `{}`", bm.short_link(&mods))), .content(format!("Beatmapset `{}`", bm.0.beatmapset_mention())),
) )
.await?; .await?;
super::display::display_beatmapset( super::display::display_beatmapset(

View file

@ -29,7 +29,7 @@ lazy_static! {
r"(?:https?://)?osu\.ppy\.sh/beatmapsets/(?P<set_id>\d+)/?(?:\#(?P<mode>osu|taiko|fruits|mania)(?:/(?P<beatmap_id>\d+)|/?))?(?:(?P<mods>v2|[[:^alpha:]]\S+\b))?" r"(?:https?://)?osu\.ppy\.sh/beatmapsets/(?P<set_id>\d+)/?(?:\#(?P<mode>osu|taiko|fruits|mania)(?:/(?P<beatmap_id>\d+)|/?))?(?:(?P<mods>v2|[[:^alpha:]]\S+\b))?"
).unwrap(); ).unwrap();
static ref SHORT_LINK_REGEX: Regex = Regex::new( static ref SHORT_LINK_REGEX: Regex = Regex::new(
r"(?:^|\s|\W)(?P<main>/b/(?P<id>\d+)(?:/(?P<mode>osu|taiko|fruits|mania))?(?:(?P<mods>v2|[[:^alpha:]]\S+\b))?)" r"(?:^|\s|\W)(?P<main>/(?P<link_type>b|s)/(?P<id>\d+)(?:/(?P<mode>osu|taiko|fruits|mania))?(?:(?P<mods>v2|[[:^alpha:]]\S+\b))?)"
).unwrap(); ).unwrap();
// Score hook // Score hook
@ -60,7 +60,7 @@ pub fn parse_old_links<'a>(
.unwrap_or_default(); .unwrap_or_default();
EmbedType::from_beatmap_id(env, capture["id"].parse()?, mode, mods).await EmbedType::from_beatmap_id(env, capture["id"].parse()?, mode, mods).await
} }
"s" => EmbedType::from_beatmapset_id(env, capture["id"].parse()?).await, "s" => EmbedType::from_beatmapset_id(env, capture["id"].parse()?, mode).await,
_ => unreachable!(), _ => unreachable!(),
}?; }?;
Ok(ToPrint { Ok(ToPrint {
@ -99,6 +99,7 @@ pub fn parse_new_links<'a>(
EmbedType::from_beatmapset_id( EmbedType::from_beatmapset_id(
env, env,
capture.name("set_id").unwrap().as_str().parse()?, capture.name("set_id").unwrap().as_str().parse()?,
mode,
) )
.await .await
} }
@ -121,11 +122,17 @@ pub fn parse_short_links<'a>(
.and_then(|v| Mode::parse_from_new_site(v.as_str())); .and_then(|v| Mode::parse_from_new_site(v.as_str()));
let link = capture.name("main").unwrap().as_str(); let link = capture.name("main").unwrap().as_str();
let id: u64 = capture.name("id").unwrap().as_str().parse()?; let id: u64 = capture.name("id").unwrap().as_str().parse()?;
let mods = capture let embed = match capture.name("link_type").unwrap().as_str() {
.name("mods") "b" => {
.and_then(|v| UnparsedMods::from_str(v.as_str()).pls_ok()) let mods = capture
.unwrap_or_default(); .name("mods")
let embed = EmbedType::from_beatmap_id(env, id, mode, mods).await?; .and_then(|v| UnparsedMods::from_str(v.as_str()).pls_ok())
.unwrap_or_default();
EmbedType::from_beatmap_id(env, id, mode, mods).await?
}
"s" => EmbedType::from_beatmapset_id(env, id, mode).await?,
_ => unreachable!(),
};
Ok(ToPrint { embed, link, mode }) Ok(ToPrint { embed, link, mode })
}) })
.collect::<stream::FuturesUnordered<_>>() .collect::<stream::FuturesUnordered<_>>()
@ -154,9 +161,13 @@ impl EmbedType {
Ok(Self::Beatmap(Box::new(bm), info, mods)) Ok(Self::Beatmap(Box::new(bm), info, mods))
} }
async fn from_beatmapset_id(env: &OsuEnv, beatmapset_id: u64) -> Result<Self> { async fn from_beatmapset_id(
env: &OsuEnv,
beatmapset_id: u64,
mode: Option<Mode>,
) -> Result<Self> {
Ok(Self::Beatmapset( Ok(Self::Beatmapset(
env.beatmaps.get_beatmapset(beatmapset_id).await?, env.beatmaps.get_beatmapset(beatmapset_id, mode).await?,
)) ))
} }
} }

View file

@ -865,7 +865,13 @@ pub async fn last(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult
Some((bm, mods_def)) => { Some((bm, mods_def)) => {
let mods = args.find::<UnparsedMods>().ok(); let mods = args.find::<UnparsedMods>().ok();
if beatmapset { if beatmapset {
let beatmapset = env.beatmaps.get_beatmapset(bm.0.beatmapset_id).await?; let beatmapset = env
.beatmaps
.get_beatmapset(
bm.0.beatmapset_id,
None, /* Note that we cannot know, so don't force that */
)
.await?;
let reply = msg let reply = msg
.reply(&ctx, "Here is the beatmapset you requested!") .reply(&ctx, "Here is the beatmapset you requested!")
.await?; .await?;