Revampt jacket loading system
This commit is contained in:
parent
cba88c5def
commit
ac4145ee40
24 changed files with 750 additions and 261 deletions
src/commands
|
@ -1,3 +1,4 @@
|
|||
use anyhow::anyhow;
|
||||
use poise::serenity_prelude::{CreateAttachment, CreateEmbed, CreateMessage};
|
||||
|
||||
use crate::{
|
||||
|
@ -25,6 +26,8 @@ use crate::{
|
|||
user::discord_id_to_discord_user,
|
||||
};
|
||||
|
||||
use super::discord::MessageContext;
|
||||
|
||||
// {{{ Top command
|
||||
/// Chart-related stats
|
||||
#[poise::command(
|
||||
|
@ -38,15 +41,9 @@ pub async fn chart(_ctx: Context<'_>) -> Result<(), Error> {
|
|||
}
|
||||
// }}}
|
||||
// {{{ Info
|
||||
/// Show a chart given it's name
|
||||
#[poise::command(prefix_command, slash_command, user_cooldown = 1)]
|
||||
async fn info(
|
||||
ctx: Context<'_>,
|
||||
#[rest]
|
||||
#[description = "Name of chart to show (difficulty at the end)"]
|
||||
name: String,
|
||||
) -> Result<(), Error> {
|
||||
let (song, chart) = guess_song_and_chart(&ctx.data(), &name)?;
|
||||
// {{{ Implementation
|
||||
async fn info_impl(ctx: &mut impl MessageContext, name: &str) -> Result<(), Error> {
|
||||
let (song, chart) = guess_song_and_chart(&ctx.data(), name)?;
|
||||
|
||||
let attachement_name = "chart.png";
|
||||
let icon_attachement = match chart.cached_jacket.as_ref() {
|
||||
|
@ -95,17 +92,62 @@ async fn info(
|
|||
embed = embed.thumbnail(format!("attachment://{}", &attachement_name));
|
||||
}
|
||||
|
||||
ctx.channel_id()
|
||||
.send_files(
|
||||
ctx.http(),
|
||||
icon_attachement,
|
||||
CreateMessage::new().embed(embed),
|
||||
)
|
||||
ctx.send_files(icon_attachement, CreateMessage::new().embed(embed))
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
// }}}
|
||||
// {{{ Tests
|
||||
#[cfg(test)]
|
||||
mod info_tests {
|
||||
use crate::{commands::discord::mock::MockContext, with_test_ctx};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn no_suffix() -> Result<(), Error> {
|
||||
with_test_ctx!("test/commands/chart/info/no_suffix", async |ctx| {
|
||||
info_impl(ctx, "Pentiment").await?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn specify_difficulty() -> Result<(), Error> {
|
||||
with_test_ctx!("test/commands/chart/info/specify_difficulty", async |ctx| {
|
||||
info_impl(ctx, "Hellohell [ETR]").await?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn last_byd() -> Result<(), Error> {
|
||||
with_test_ctx!(
|
||||
"test/commands/chart/info/last_byd",
|
||||
async |ctx: &mut MockContext| {
|
||||
info_impl(ctx, "Last | Moment [BYD]").await?;
|
||||
info_impl(ctx, "Last | Eternity [BYD]").await?;
|
||||
Ok(())
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
// }}}
|
||||
|
||||
/// Show a chart given it's name
|
||||
#[poise::command(prefix_command, slash_command, user_cooldown = 1)]
|
||||
async fn info(
|
||||
mut ctx: Context<'_>,
|
||||
#[rest]
|
||||
#[description = "Name of chart to show (difficulty at the end)"]
|
||||
name: String,
|
||||
) -> Result<(), Error> {
|
||||
info_impl(&mut ctx, &name).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
// }}}
|
||||
// {{{ Best score
|
||||
/// Show the best score on a given chart
|
||||
#[poise::command(prefix_command, slash_command, user_cooldown = 1)]
|
||||
|
@ -138,9 +180,10 @@ async fn best(
|
|||
)?
|
||||
.query_row((user.id, chart.id), |row| Play::from_sql(chart, row))
|
||||
.map_err(|_| {
|
||||
format!(
|
||||
anyhow!(
|
||||
"Could not find any scores for {} [{:?}]",
|
||||
song.title, chart.difficulty
|
||||
song.title,
|
||||
chart.difficulty
|
||||
)
|
||||
})?;
|
||||
|
||||
|
|
|
@ -53,9 +53,7 @@ pub trait MessageContext {
|
|||
}
|
||||
// }}}
|
||||
// {{{ Poise implementation
|
||||
impl<'a, 'b> MessageContext
|
||||
for poise::Context<'a, UserContext, Box<dyn std::error::Error + Send + Sync + 'b>>
|
||||
{
|
||||
impl<'a> MessageContext for poise::Context<'a, UserContext, Error> {
|
||||
type Attachment = poise::serenity_prelude::Attachment;
|
||||
|
||||
fn data(&self) -> &UserContext {
|
||||
|
|
|
@ -4,6 +4,7 @@ use crate::context::{Context, Error};
|
|||
use crate::recognition::recognize::{ImageAnalyzer, ScoreKind};
|
||||
use crate::user::{discord_id_to_discord_user, User};
|
||||
use crate::{get_user, timed};
|
||||
use anyhow::anyhow;
|
||||
use image::DynamicImage;
|
||||
use poise::serenity_prelude as serenity;
|
||||
use poise::serenity_prelude::CreateMessage;
|
||||
|
@ -90,9 +91,10 @@ async fn magic_impl<C: MessageContext>(
|
|||
analyzer
|
||||
.read_score(ctx.data(), Some(chart.note_count), &grayscale_image, kind)
|
||||
.map_err(|err| {
|
||||
format!(
|
||||
anyhow!(
|
||||
"Could not read score for chart {} [{:?}]: {err}",
|
||||
song.title, chart.difficulty
|
||||
song.title,
|
||||
chart.difficulty
|
||||
)
|
||||
})?
|
||||
});
|
||||
|
@ -137,52 +139,24 @@ async fn magic_impl<C: MessageContext>(
|
|||
// {{{ Tests
|
||||
#[cfg(test)]
|
||||
mod magic_tests {
|
||||
use std::{path::PathBuf, process::Command, str::FromStr};
|
||||
|
||||
use r2d2_sqlite::SqliteConnectionManager;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::{
|
||||
commands::discord::mock::MockContext,
|
||||
context::{connect_db, get_shared_context},
|
||||
};
|
||||
use crate::with_test_ctx;
|
||||
|
||||
use super::*;
|
||||
|
||||
macro_rules! with_ctx {
|
||||
($test_path:expr, $f:expr) => {{
|
||||
let mut data = (*get_shared_context().await).clone();
|
||||
let dir = tempfile::tempdir()?;
|
||||
let path = dir.path().join("db.sqlite");
|
||||
println!("path {path:?}");
|
||||
data.db = connect_db(SqliteConnectionManager::file(path));
|
||||
|
||||
Command::new("scripts/import-charts.py")
|
||||
.env("SHIMMERING_DATA_DIR", dir.path().to_str().unwrap())
|
||||
.output()
|
||||
.unwrap();
|
||||
|
||||
let mut ctx = MockContext::new(data);
|
||||
User::create_from_context(&ctx)?;
|
||||
|
||||
let res: Result<(), Error> = $f(&mut ctx).await;
|
||||
res?;
|
||||
|
||||
ctx.write_to(&PathBuf::from_str($test_path)?)?;
|
||||
Ok(())
|
||||
}};
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn no_pics() -> Result<(), Error> {
|
||||
with_ctx!("test/commands/score/magic/no_pics", async |ctx| {
|
||||
with_test_ctx!("test/commands/score/magic/no_pics", async |ctx| {
|
||||
magic_impl(ctx, vec![]).await?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn basic_pic() -> Result<(), Error> {
|
||||
with_ctx!("test/commands/score/magic/single_pic", async |ctx| {
|
||||
async fn simple_pic() -> Result<(), Error> {
|
||||
with_test_ctx!("test/commands/score/magic/single_pic", async |ctx| {
|
||||
magic_impl(
|
||||
ctx,
|
||||
vec![PathBuf::from_str("test/screenshots/alter_ego.jpg")?],
|
||||
|
@ -194,7 +168,7 @@ mod magic_tests {
|
|||
|
||||
#[tokio::test]
|
||||
async fn weird_kerning() -> Result<(), Error> {
|
||||
with_ctx!("test/commands/score/magic/weird_kerning", async |ctx| {
|
||||
with_test_ctx!("test/commands/score/magic/weird_kerning", async |ctx| {
|
||||
magic_impl(
|
||||
ctx,
|
||||
vec![
|
||||
|
@ -298,7 +272,7 @@ pub async fn show(
|
|||
Ok((song, chart, play, discord_id))
|
||||
})?
|
||||
.next()
|
||||
.ok_or_else(|| format!("Could not find play with id {}", id))??;
|
||||
.ok_or_else(|| anyhow!("Could not find play with id {}", id))??;
|
||||
|
||||
let author = discord_id_to_discord_user(&ctx, &discord_id).await?;
|
||||
let user = User::by_id(ctx.data(), play.user_id)?;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::io::Cursor;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use image::{DynamicImage, ImageBuffer};
|
||||
use poise::{
|
||||
serenity_prelude::{CreateAttachment, CreateEmbed},
|
||||
|
@ -194,9 +195,10 @@ async fn best_plays(
|
|||
// }}}
|
||||
// {{{ Display jacket
|
||||
let jacket = chart.cached_jacket.as_ref().ok_or_else(|| {
|
||||
format!(
|
||||
anyhow!(
|
||||
"Cannot find jacket for chart {} [{:?}]",
|
||||
song.title, chart.difficulty
|
||||
song.title,
|
||||
chart.difficulty
|
||||
)
|
||||
})?;
|
||||
|
||||
|
@ -289,7 +291,7 @@ async fn best_plays(
|
|||
// {{{ Display status text
|
||||
with_font(&EXO_FONT, |faces| {
|
||||
let status = play.short_status(scoring_system, chart).ok_or_else(|| {
|
||||
format!(
|
||||
anyhow!(
|
||||
"Could not get status for score {}",
|
||||
play.score(scoring_system)
|
||||
)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue