Build the project on stable rust
This commit is contained in:
parent
5bc6dfa667
commit
8d3c26b036
31
Cargo.lock
generated
31
Cargo.lock
generated
|
@ -173,9 +173,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-trait"
|
name = "async-trait"
|
||||||
version = "0.1.82"
|
version = "0.1.86"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1"
|
checksum = "644dd749086bf3771a2fbc5f256fdb982d53f011c7d5d560304eafeecebce79d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -219,14 +219,14 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "axum"
|
name = "axum"
|
||||||
version = "0.7.6"
|
version = "0.8.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8f43644eed690f5374f1af436ecd6aea01cd201f6fbdf0178adaf6907afb2cec"
|
checksum = "6d6fd624c75e18b3b4c6b9caf42b1afe24437daaee904069137d8bab077be8b8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
|
||||||
"axum-core",
|
"axum-core",
|
||||||
"axum-macros",
|
"axum-macros",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
"form_urlencoded",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http 1.1.0",
|
"http 1.1.0",
|
||||||
"http-body 1.0.1",
|
"http-body 1.0.1",
|
||||||
|
@ -246,7 +246,7 @@ dependencies = [
|
||||||
"serde_urlencoded",
|
"serde_urlencoded",
|
||||||
"sync_wrapper 1.0.1",
|
"sync_wrapper 1.0.1",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tower 0.5.1",
|
"tower 0.5.2",
|
||||||
"tower-layer",
|
"tower-layer",
|
||||||
"tower-service",
|
"tower-service",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
@ -254,11 +254,10 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "axum-core"
|
name = "axum-core"
|
||||||
version = "0.4.4"
|
version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5e6b8ba012a258d63c9adfa28b9ddcf66149da6f986c5b5452e629d5ee64bf00"
|
checksum = "df1362f362fd16024ae199c1970ce98f9661bf5ef94b9808fee734bc3698b733"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http 1.1.0",
|
"http 1.1.0",
|
||||||
|
@ -275,9 +274,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "axum-macros"
|
name = "axum-macros"
|
||||||
version = "0.4.2"
|
version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "57d123550fa8d071b7255cb0cc04dc302baa6c8c4a79f55701552684d8399bce"
|
checksum = "604fde5e028fea851ce1d8570bbdc034bec850d157f7569d10f347d06808c05c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -2002,9 +2001,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "matchit"
|
name = "matchit"
|
||||||
version = "0.7.3"
|
version = "0.8.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94"
|
checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "matrixcompare"
|
name = "matrixcompare"
|
||||||
|
@ -3924,14 +3923,14 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tower"
|
name = "tower"
|
||||||
version = "0.5.1"
|
version = "0.5.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f"
|
checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"sync_wrapper 0.1.2",
|
"sync_wrapper 1.0.1",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tower-layer",
|
"tower-layer",
|
||||||
"tower-service",
|
"tower-service",
|
||||||
|
|
|
@ -46,7 +46,7 @@ postcard = { version = "1.0.10", features = ["use-std"], default-features = fals
|
||||||
anyhow = "1.0.87"
|
anyhow = "1.0.87"
|
||||||
sha2 = "0.10.8"
|
sha2 = "0.10.8"
|
||||||
base16ct = { version = "0.2.0", features = ["alloc"] }
|
base16ct = { version = "0.2.0", features = ["alloc"] }
|
||||||
axum = { version = "0.7.6", features = ["macros"] }
|
axum = { version = "0.8.1", features = ["macros"] }
|
||||||
paste = "1.0.15"
|
paste = "1.0.15"
|
||||||
discord-rich-presence = "0.2.4"
|
discord-rich-presence = "0.2.4"
|
||||||
reqwest = { version = "0.12.7", features = ["json"] }
|
reqwest = { version = "0.12.7", features = ["json"] }
|
||||||
|
|
|
@ -24,6 +24,8 @@ No neural-networks/machine-learning is used by this project. All image analysis
|
||||||
|
|
||||||
## Running locally
|
## Running locally
|
||||||
|
|
||||||
|
> WARNING: the instructions in this file are a bit outdated.
|
||||||
|
|
||||||
The programs need (sometimes a subset of) the following environment variables in order to run:
|
The programs need (sometimes a subset of) the following environment variables in order to run:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
39
flake.lock
39
flake.lock
|
@ -1,26 +1,5 @@
|
||||||
{
|
{
|
||||||
"nodes": {
|
"nodes": {
|
||||||
"fenix": {
|
|
||||||
"inputs": {
|
|
||||||
"nixpkgs": [
|
|
||||||
"nixpkgs"
|
|
||||||
],
|
|
||||||
"rust-analyzer-src": "rust-analyzer-src"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1739169164,
|
|
||||||
"narHash": "sha256-2+/6/2rHsMjlrulkrjZbwthCQiQpeW2pukRFaaUMLy8=",
|
|
||||||
"owner": "nix-community",
|
|
||||||
"repo": "fenix",
|
|
||||||
"rev": "d7616af878cd0cb7f940b470440347920395be0c",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nix-community",
|
|
||||||
"repo": "fenix",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"flake-utils": {
|
"flake-utils": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"systems": "systems"
|
"systems": "systems"
|
||||||
|
@ -57,29 +36,11 @@
|
||||||
},
|
},
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"fenix": "fenix",
|
|
||||||
"flake-utils": "flake-utils",
|
"flake-utils": "flake-utils",
|
||||||
"nixpkgs": "nixpkgs",
|
"nixpkgs": "nixpkgs",
|
||||||
"shimmeringdarkness": "shimmeringdarkness"
|
"shimmeringdarkness": "shimmeringdarkness"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rust-analyzer-src": {
|
|
||||||
"flake": false,
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1739099919,
|
|
||||||
"narHash": "sha256-YUdM2yZzQIbakgc2LdVmkgJMYTqeTu3YdWGgFfiZiTg=",
|
|
||||||
"owner": "rust-lang",
|
|
||||||
"repo": "rust-analyzer",
|
|
||||||
"rev": "35181e167efb94d5090df588e6af9f93250421f3",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "rust-lang",
|
|
||||||
"ref": "nightly",
|
|
||||||
"repo": "rust-analyzer",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"shimmeringdarkness": {
|
"shimmeringdarkness": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
|
|
19
flake.nix
19
flake.nix
|
@ -2,8 +2,6 @@
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||||
flake-utils.url = "github:numtide/flake-utils";
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
fenix.url = "github:nix-community/fenix";
|
|
||||||
fenix.inputs.nixpkgs.follows = "nixpkgs";
|
|
||||||
shimmeringdarkness.url = "git+ssh://forgejo@ssh.git.moonythm.dev/prescientmoon/shimmeringdarkness.git";
|
shimmeringdarkness.url = "git+ssh://forgejo@ssh.git.moonythm.dev/prescientmoon/shimmeringdarkness.git";
|
||||||
shimmeringdarkness.flake = false;
|
shimmeringdarkness.flake = false;
|
||||||
};
|
};
|
||||||
|
@ -13,15 +11,12 @@
|
||||||
inputs.flake-utils.lib.eachSystem (with inputs.flake-utils.lib.system; [ x86_64-linux ]) (
|
inputs.flake-utils.lib.eachSystem (with inputs.flake-utils.lib.system; [ x86_64-linux ]) (
|
||||||
system:
|
system:
|
||||||
let
|
let
|
||||||
pkgs = inputs.nixpkgs.legacyPackages.${system}.extend inputs.fenix.overlays.default;
|
pkgs = inputs.nixpkgs.legacyPackages.${system};
|
||||||
rust-toolchain = pkgs.fenix.complete.toolchain;
|
|
||||||
spkgs = inputs.self.packages.${system};
|
spkgs = inputs.self.packages.${system};
|
||||||
inherit (pkgs) lib;
|
inherit (pkgs) lib;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
packages = {
|
packages = {
|
||||||
inherit rust-toolchain;
|
|
||||||
|
|
||||||
# {{{ Private config
|
# {{{ Private config
|
||||||
shimmeringdarkness = inputs.shimmeringdarkness.outPath;
|
shimmeringdarkness = inputs.shimmeringdarkness.outPath;
|
||||||
glass-bundler = pkgs.callPackage ./nix/glass-bundler.nix { };
|
glass-bundler = pkgs.callPackage ./nix/glass-bundler.nix { };
|
||||||
|
@ -43,23 +38,27 @@
|
||||||
inherit (spkgs) exo kazesawa geosans-light;
|
inherit (spkgs) exo kazesawa geosans-light;
|
||||||
};
|
};
|
||||||
# }}}
|
# }}}
|
||||||
|
# {{{ Shimmeringmoon
|
||||||
cc-data = pkgs.callPackage ./nix/cc-data.nix { };
|
cc-data = pkgs.callPackage ./nix/cc-data.nix { };
|
||||||
default = spkgs.shimmeringmoon;
|
default = spkgs.shimmeringmoon;
|
||||||
shimmeringmoon = pkgs.callPackage ./nix/shimmeringmoon.nix {
|
shimmeringmoon = pkgs.callPackage ./nix/shimmeringmoon.nix {
|
||||||
inherit (spkgs)
|
inherit (spkgs)
|
||||||
shimmering-fonts
|
shimmering-fonts
|
||||||
rust-toolchain
|
|
||||||
cc-data
|
cc-data
|
||||||
private-config
|
private-config
|
||||||
;
|
;
|
||||||
};
|
};
|
||||||
|
# }}}
|
||||||
};
|
};
|
||||||
|
|
||||||
# {{{ Devshell
|
# {{{ Devshell
|
||||||
devShell = pkgs.mkShell rec {
|
devShell = pkgs.mkShell rec {
|
||||||
nativeBuildInputs = with pkgs; [
|
nativeBuildInputs = [
|
||||||
spkgs.rust-toolchain
|
pkgs.rustc
|
||||||
|
pkgs.cargo
|
||||||
|
pkgs.rustfmt
|
||||||
|
pkgs.clippy
|
||||||
|
pkgs.rust-analyzer
|
||||||
|
|
||||||
pkgs.ruff
|
pkgs.ruff
|
||||||
pkgs.imagemagick
|
pkgs.imagemagick
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
{
|
{
|
||||||
lib,
|
|
||||||
pkg-config,
|
pkg-config,
|
||||||
makeWrapper,
|
makeWrapper,
|
||||||
|
|
||||||
|
@ -7,19 +6,12 @@
|
||||||
fontconfig,
|
fontconfig,
|
||||||
openssl,
|
openssl,
|
||||||
sqlite,
|
sqlite,
|
||||||
makeRustPlatform,
|
rustPlatform,
|
||||||
rust-toolchain,
|
|
||||||
|
|
||||||
shimmering-fonts,
|
shimmering-fonts,
|
||||||
cc-data,
|
cc-data,
|
||||||
private-config,
|
private-config,
|
||||||
}:
|
}:
|
||||||
let
|
|
||||||
rustPlatform = makeRustPlatform {
|
|
||||||
cargo = rust-toolchain;
|
|
||||||
rustc = rust-toolchain;
|
|
||||||
};
|
|
||||||
in
|
|
||||||
rustPlatform.buildRustPackage rec {
|
rustPlatform.buildRustPackage rec {
|
||||||
pname = "shimmeringmoon";
|
pname = "shimmeringmoon";
|
||||||
version = "unstable-2025-02-11";
|
version = "unstable-2025-02-11";
|
||||||
|
|
|
@ -32,8 +32,8 @@ async fn main() -> anyhow::Result<()> {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let (Ok(global_prefix)) = global_prefix {
|
if let Ok(global_prefix) = global_prefix {
|
||||||
if message.content.starts_with(global_prefix) {
|
if message.content.starts_with(&global_prefix) {
|
||||||
return Ok(Some(message.content.split_at(global_prefix.len())));
|
return Ok(Some(message.content.split_at(global_prefix.len())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ async fn main() -> anyhow::Result<()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(None);
|
Ok(None)
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
edit_tracker: Some(Arc::new(poise::EditTracker::for_timespan(
|
edit_tracker: Some(Arc::new(poise::EditTracker::for_timespan(
|
||||||
|
|
|
@ -4,9 +4,10 @@ use crate::arcaea::score::Score;
|
||||||
use crate::context::{Error, ErrorKind, PoiseContext, TagError, TaggedError};
|
use crate::context::{Error, ErrorKind, PoiseContext, TagError, TaggedError};
|
||||||
use crate::recognition::recognize::{ImageAnalyzer, ScoreKind};
|
use crate::recognition::recognize::{ImageAnalyzer, ScoreKind};
|
||||||
use crate::user::User;
|
use crate::user::User;
|
||||||
use crate::{async_try_block, get_user_error, timed};
|
use crate::{get_user_error, timed};
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use image::DynamicImage;
|
use image::DynamicImage;
|
||||||
|
use poise::serenity_prelude::{CreateAttachment, CreateEmbed};
|
||||||
use poise::{serenity_prelude as serenity, CreateReply};
|
use poise::{serenity_prelude as serenity, CreateReply};
|
||||||
|
|
||||||
use super::discord::{CreateReplyExtra, MessageContext};
|
use super::discord::{CreateReplyExtra, MessageContext};
|
||||||
|
@ -26,6 +27,83 @@ pub async fn score(_ctx: PoiseContext<'_>) -> Result<(), Error> {
|
||||||
// }}}
|
// }}}
|
||||||
// {{{ Score magic
|
// {{{ Score magic
|
||||||
// {{{ Implementation
|
// {{{ Implementation
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
async fn magic_detect_one<C: MessageContext>(
|
||||||
|
ctx: &mut C,
|
||||||
|
user: &User,
|
||||||
|
embeds: &mut Vec<CreateEmbed>,
|
||||||
|
attachments: &mut Vec<CreateAttachment>,
|
||||||
|
plays: &mut Vec<Play>,
|
||||||
|
analyzer: &mut ImageAnalyzer,
|
||||||
|
attachment: &C::Attachment,
|
||||||
|
index: usize,
|
||||||
|
image: &mut DynamicImage,
|
||||||
|
grayscale_image: &mut DynamicImage,
|
||||||
|
) -> Result<(), TaggedError> {
|
||||||
|
// {{{ Detection
|
||||||
|
let kind = timed!("read_score_kind", {
|
||||||
|
analyzer.read_score_kind(ctx.data(), grayscale_image)?
|
||||||
|
});
|
||||||
|
|
||||||
|
let difficulty = timed!("read_difficulty", {
|
||||||
|
analyzer.read_difficulty(ctx.data(), image, grayscale_image, kind)?
|
||||||
|
});
|
||||||
|
|
||||||
|
let (song, chart) = timed!("read_jacket", {
|
||||||
|
analyzer.read_jacket(ctx.data(), image, kind, difficulty)?
|
||||||
|
});
|
||||||
|
|
||||||
|
let max_recall = match kind {
|
||||||
|
ScoreKind::ScoreScreen => {
|
||||||
|
// NOTE: are we ok with discarding errors like that?
|
||||||
|
analyzer.read_max_recall(ctx.data(), grayscale_image).ok()
|
||||||
|
}
|
||||||
|
ScoreKind::SongSelect => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
grayscale_image.invert();
|
||||||
|
let note_distribution = match kind {
|
||||||
|
ScoreKind::ScoreScreen => Some(analyzer.read_distribution(ctx.data(), grayscale_image)?),
|
||||||
|
ScoreKind::SongSelect => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let score = timed!("read_score", {
|
||||||
|
analyzer
|
||||||
|
.read_score(ctx.data(), Some(chart.note_count), grayscale_image, kind)
|
||||||
|
.map_err(|err| {
|
||||||
|
anyhow!(
|
||||||
|
"Could not read score for chart {} [{:?}]: {err}",
|
||||||
|
song.title,
|
||||||
|
chart.difficulty
|
||||||
|
)
|
||||||
|
})?
|
||||||
|
});
|
||||||
|
|
||||||
|
// {{{ Build play
|
||||||
|
let maybe_fars =
|
||||||
|
Score::resolve_distibution_ambiguities(score, note_distribution, chart.note_count);
|
||||||
|
|
||||||
|
let play = CreatePlay::new(score)
|
||||||
|
.with_attachment(C::attachment_id(attachment))
|
||||||
|
.with_fars(maybe_fars)
|
||||||
|
.with_max_recall(max_recall)
|
||||||
|
.save(ctx.data(), user, chart)
|
||||||
|
.await?;
|
||||||
|
// }}}
|
||||||
|
// }}}
|
||||||
|
// {{{ Deliver embed
|
||||||
|
let (embed, attachment) = timed!("to embed", {
|
||||||
|
play.to_embed(ctx.data(), user, song, chart, index, None)?
|
||||||
|
});
|
||||||
|
|
||||||
|
plays.push(play);
|
||||||
|
embeds.push(embed);
|
||||||
|
attachments.extend(attachment);
|
||||||
|
// }}}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn magic_impl<C: MessageContext>(
|
pub async fn magic_impl<C: MessageContext>(
|
||||||
ctx: &mut C,
|
ctx: &mut C,
|
||||||
files: &[C::Attachment],
|
files: &[C::Attachment],
|
||||||
|
@ -43,76 +121,23 @@ pub async fn magic_impl<C: MessageContext>(
|
||||||
let mut analyzer = ImageAnalyzer::default();
|
let mut analyzer = ImageAnalyzer::default();
|
||||||
|
|
||||||
for (i, (attachment, bytes)) in files.into_iter().enumerate() {
|
for (i, (attachment, bytes)) in files.into_iter().enumerate() {
|
||||||
// {{{ Preapare image
|
// {{{ Process attachment
|
||||||
let mut image = image::load_from_memory(&bytes)?;
|
let mut image = image::load_from_memory(&bytes)?;
|
||||||
let mut grayscale_image = DynamicImage::ImageLuma8(image.to_luma8());
|
let mut grayscale_image = DynamicImage::ImageLuma8(image.to_luma8());
|
||||||
// }}}
|
|
||||||
|
|
||||||
let result: Result<(), TaggedError> = async_try_block!({
|
let result = magic_detect_one(
|
||||||
// {{{ Detection
|
ctx,
|
||||||
|
&user,
|
||||||
let kind = timed!("read_score_kind", {
|
&mut embeds,
|
||||||
analyzer.read_score_kind(ctx.data(), &grayscale_image)?
|
&mut attachments,
|
||||||
});
|
&mut plays,
|
||||||
|
&mut analyzer,
|
||||||
let difficulty = timed!("read_difficulty", {
|
attachment,
|
||||||
analyzer.read_difficulty(ctx.data(), &image, &grayscale_image, kind)?
|
i,
|
||||||
});
|
&mut image,
|
||||||
|
&mut grayscale_image,
|
||||||
let (song, chart) = timed!("read_jacket", {
|
)
|
||||||
analyzer.read_jacket(ctx.data(), &mut image, kind, difficulty)?
|
.await;
|
||||||
});
|
|
||||||
|
|
||||||
let max_recall = match kind {
|
|
||||||
ScoreKind::ScoreScreen => {
|
|
||||||
// NOTE: are we ok with discarding errors like that?
|
|
||||||
analyzer.read_max_recall(ctx.data(), &grayscale_image).ok()
|
|
||||||
}
|
|
||||||
ScoreKind::SongSelect => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
grayscale_image.invert();
|
|
||||||
let note_distribution = match kind {
|
|
||||||
ScoreKind::ScoreScreen => {
|
|
||||||
Some(analyzer.read_distribution(ctx.data(), &grayscale_image)?)
|
|
||||||
}
|
|
||||||
ScoreKind::SongSelect => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
let score = timed!("read_score", {
|
|
||||||
analyzer
|
|
||||||
.read_score(ctx.data(), Some(chart.note_count), &grayscale_image, kind)
|
|
||||||
.map_err(|err| {
|
|
||||||
anyhow!(
|
|
||||||
"Could not read score for chart {} [{:?}]: {err}",
|
|
||||||
song.title,
|
|
||||||
chart.difficulty
|
|
||||||
)
|
|
||||||
})?
|
|
||||||
});
|
|
||||||
|
|
||||||
// {{{ Build play
|
|
||||||
let maybe_fars =
|
|
||||||
Score::resolve_distibution_ambiguities(score, note_distribution, chart.note_count);
|
|
||||||
|
|
||||||
let play = CreatePlay::new(score)
|
|
||||||
.with_attachment(C::attachment_id(attachment))
|
|
||||||
.with_fars(maybe_fars)
|
|
||||||
.with_max_recall(max_recall)
|
|
||||||
.save(ctx.data(), &user, chart)
|
|
||||||
.await?;
|
|
||||||
// }}}
|
|
||||||
// }}}
|
|
||||||
// {{{ Deliver embed
|
|
||||||
let (embed, attachment) = timed!("to embed", {
|
|
||||||
play.to_embed(ctx.data(), &user, song, chart, i, None)?
|
|
||||||
});
|
|
||||||
|
|
||||||
plays.push(play);
|
|
||||||
embeds.push(embed);
|
|
||||||
attachments.extend(attachment);
|
|
||||||
// }}}
|
|
||||||
});
|
|
||||||
|
|
||||||
if let Err(err) = result {
|
if let Err(err) = result {
|
||||||
let user_err = get_user_error!(err);
|
let user_err = get_user_error!(err);
|
||||||
|
@ -120,6 +145,7 @@ pub async fn magic_impl<C: MessageContext>(
|
||||||
.send_discord_error(ctx, &image, C::filename(attachment), user_err)
|
.send_discord_error(ctx, &image, C::filename(attachment), user_err)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
// }}}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !embeds.is_empty() {
|
if !embeds.is_empty() {
|
||||||
|
|
|
@ -27,6 +27,5 @@ pub fn hash_bytes(bytes: &[u8]) -> String {
|
||||||
let mut hasher = Sha256::default();
|
let mut hasher = Sha256::default();
|
||||||
hasher.update(bytes);
|
hasher.update(bytes);
|
||||||
let res = hasher.finalize();
|
let res = hasher.finalize();
|
||||||
let string = base16ct::lower::encode_string(&res);
|
base16ct::lower::encode_string(&res)
|
||||||
string
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,4 +17,3 @@ pub mod recognition;
|
||||||
pub mod time;
|
pub mod time;
|
||||||
pub mod transform;
|
pub mod transform;
|
||||||
pub mod user;
|
pub mod user;
|
||||||
mod utils;
|
|
||||||
|
|
29
src/utils.rs
29
src/utils.rs
|
@ -1,29 +0,0 @@
|
||||||
/// Performs "Ok-wrapping" on the result of an expression.
|
|
||||||
/// This is compatible with [`Result`], [`Option`], [`ControlFlow`], and any type that
|
|
||||||
/// implements the unstable [`std::ops::Try`] trait.
|
|
||||||
///
|
|
||||||
/// The destination type must be specified with a type ascription somewhere.
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! wrap_ok {
|
|
||||||
($e:expr) => {
|
|
||||||
::core::iter::empty().try_fold($e, |_, __x: ::core::convert::Infallible| match __x {})
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! try_block {
|
|
||||||
{ $($token:tt)* } => {
|
|
||||||
(|| $crate::wrap_ok!({
|
|
||||||
$($token)*
|
|
||||||
}))()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! async_try_block {
|
|
||||||
{ $($token:tt)* } => {
|
|
||||||
(async || $crate::wrap_ok!({
|
|
||||||
$($token)*
|
|
||||||
}))().await
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue