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]]
|
||||
name = "async-trait"
|
||||
version = "0.1.82"
|
||||
version = "0.1.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1"
|
||||
checksum = "644dd749086bf3771a2fbc5f256fdb982d53f011c7d5d560304eafeecebce79d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -219,14 +219,14 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "axum"
|
||||
version = "0.7.6"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f43644eed690f5374f1af436ecd6aea01cd201f6fbdf0178adaf6907afb2cec"
|
||||
checksum = "6d6fd624c75e18b3b4c6b9caf42b1afe24437daaee904069137d8bab077be8b8"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum-core",
|
||||
"axum-macros",
|
||||
"bytes",
|
||||
"form_urlencoded",
|
||||
"futures-util",
|
||||
"http 1.1.0",
|
||||
"http-body 1.0.1",
|
||||
|
@ -246,7 +246,7 @@ dependencies = [
|
|||
"serde_urlencoded",
|
||||
"sync_wrapper 1.0.1",
|
||||
"tokio",
|
||||
"tower 0.5.1",
|
||||
"tower 0.5.2",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
|
@ -254,11 +254,10 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "axum-core"
|
||||
version = "0.4.4"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e6b8ba012a258d63c9adfa28b9ddcf66149da6f986c5b5452e629d5ee64bf00"
|
||||
checksum = "df1362f362fd16024ae199c1970ce98f9661bf5ef94b9808fee734bc3698b733"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http 1.1.0",
|
||||
|
@ -275,9 +274,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "axum-macros"
|
||||
version = "0.4.2"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57d123550fa8d071b7255cb0cc04dc302baa6c8c4a79f55701552684d8399bce"
|
||||
checksum = "604fde5e028fea851ce1d8570bbdc034bec850d157f7569d10f347d06808c05c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -2002,9 +2001,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "matchit"
|
||||
version = "0.7.3"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94"
|
||||
checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3"
|
||||
|
||||
[[package]]
|
||||
name = "matrixcompare"
|
||||
|
@ -3924,14 +3923,14 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tower"
|
||||
version = "0.5.1"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f"
|
||||
checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"pin-project-lite",
|
||||
"sync_wrapper 0.1.2",
|
||||
"sync_wrapper 1.0.1",
|
||||
"tokio",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
|
|
|
@ -46,7 +46,7 @@ postcard = { version = "1.0.10", features = ["use-std"], default-features = fals
|
|||
anyhow = "1.0.87"
|
||||
sha2 = "0.10.8"
|
||||
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"
|
||||
discord-rich-presence = "0.2.4"
|
||||
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
|
||||
|
||||
> 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:
|
||||
|
||||
```
|
||||
|
|
39
flake.lock
39
flake.lock
|
@ -1,26 +1,5 @@
|
|||
{
|
||||
"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": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
|
@ -57,29 +36,11 @@
|
|||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"fenix": "fenix",
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"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": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
|
|
19
flake.nix
19
flake.nix
|
@ -2,8 +2,6 @@
|
|||
inputs = {
|
||||
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||
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.flake = false;
|
||||
};
|
||||
|
@ -13,15 +11,12 @@
|
|||
inputs.flake-utils.lib.eachSystem (with inputs.flake-utils.lib.system; [ x86_64-linux ]) (
|
||||
system:
|
||||
let
|
||||
pkgs = inputs.nixpkgs.legacyPackages.${system}.extend inputs.fenix.overlays.default;
|
||||
rust-toolchain = pkgs.fenix.complete.toolchain;
|
||||
pkgs = inputs.nixpkgs.legacyPackages.${system};
|
||||
spkgs = inputs.self.packages.${system};
|
||||
inherit (pkgs) lib;
|
||||
in
|
||||
{
|
||||
packages = {
|
||||
inherit rust-toolchain;
|
||||
|
||||
# {{{ Private config
|
||||
shimmeringdarkness = inputs.shimmeringdarkness.outPath;
|
||||
glass-bundler = pkgs.callPackage ./nix/glass-bundler.nix { };
|
||||
|
@ -43,23 +38,27 @@
|
|||
inherit (spkgs) exo kazesawa geosans-light;
|
||||
};
|
||||
# }}}
|
||||
|
||||
# {{{ Shimmeringmoon
|
||||
cc-data = pkgs.callPackage ./nix/cc-data.nix { };
|
||||
default = spkgs.shimmeringmoon;
|
||||
shimmeringmoon = pkgs.callPackage ./nix/shimmeringmoon.nix {
|
||||
inherit (spkgs)
|
||||
shimmering-fonts
|
||||
rust-toolchain
|
||||
cc-data
|
||||
private-config
|
||||
;
|
||||
};
|
||||
# }}}
|
||||
};
|
||||
|
||||
# {{{ Devshell
|
||||
devShell = pkgs.mkShell rec {
|
||||
nativeBuildInputs = with pkgs; [
|
||||
spkgs.rust-toolchain
|
||||
nativeBuildInputs = [
|
||||
pkgs.rustc
|
||||
pkgs.cargo
|
||||
pkgs.rustfmt
|
||||
pkgs.clippy
|
||||
pkgs.rust-analyzer
|
||||
|
||||
pkgs.ruff
|
||||
pkgs.imagemagick
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
{
|
||||
lib,
|
||||
pkg-config,
|
||||
makeWrapper,
|
||||
|
||||
|
@ -7,19 +6,12 @@
|
|||
fontconfig,
|
||||
openssl,
|
||||
sqlite,
|
||||
makeRustPlatform,
|
||||
rust-toolchain,
|
||||
rustPlatform,
|
||||
|
||||
shimmering-fonts,
|
||||
cc-data,
|
||||
private-config,
|
||||
}:
|
||||
let
|
||||
rustPlatform = makeRustPlatform {
|
||||
cargo = rust-toolchain;
|
||||
rustc = rust-toolchain;
|
||||
};
|
||||
in
|
||||
rustPlatform.buildRustPackage rec {
|
||||
pname = "shimmeringmoon";
|
||||
version = "unstable-2025-02-11";
|
||||
|
|
|
@ -32,8 +32,8 @@ async fn main() -> anyhow::Result<()> {
|
|||
return Ok(None);
|
||||
}
|
||||
|
||||
if let (Ok(global_prefix)) = global_prefix {
|
||||
if message.content.starts_with(global_prefix) {
|
||||
if let Ok(global_prefix) = global_prefix {
|
||||
if message.content.starts_with(&global_prefix) {
|
||||
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(
|
||||
|
|
|
@ -4,9 +4,10 @@ use crate::arcaea::score::Score;
|
|||
use crate::context::{Error, ErrorKind, PoiseContext, TagError, TaggedError};
|
||||
use crate::recognition::recognize::{ImageAnalyzer, ScoreKind};
|
||||
use crate::user::User;
|
||||
use crate::{async_try_block, get_user_error, timed};
|
||||
use crate::{get_user_error, timed};
|
||||
use anyhow::anyhow;
|
||||
use image::DynamicImage;
|
||||
use poise::serenity_prelude::{CreateAttachment, CreateEmbed};
|
||||
use poise::{serenity_prelude as serenity, CreateReply};
|
||||
|
||||
use super::discord::{CreateReplyExtra, MessageContext};
|
||||
|
@ -26,6 +27,83 @@ pub async fn score(_ctx: PoiseContext<'_>) -> Result<(), Error> {
|
|||
// }}}
|
||||
// {{{ Score magic
|
||||
// {{{ 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>(
|
||||
ctx: &mut C,
|
||||
files: &[C::Attachment],
|
||||
|
@ -43,76 +121,23 @@ pub async fn magic_impl<C: MessageContext>(
|
|||
let mut analyzer = ImageAnalyzer::default();
|
||||
|
||||
for (i, (attachment, bytes)) in files.into_iter().enumerate() {
|
||||
// {{{ Preapare image
|
||||
// {{{ Process attachment
|
||||
let mut image = image::load_from_memory(&bytes)?;
|
||||
let mut grayscale_image = DynamicImage::ImageLuma8(image.to_luma8());
|
||||
// }}}
|
||||
|
||||
let result: Result<(), TaggedError> = async_try_block!({
|
||||
// {{{ 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(), &mut 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, i, None)?
|
||||
});
|
||||
|
||||
plays.push(play);
|
||||
embeds.push(embed);
|
||||
attachments.extend(attachment);
|
||||
// }}}
|
||||
});
|
||||
let result = magic_detect_one(
|
||||
ctx,
|
||||
&user,
|
||||
&mut embeds,
|
||||
&mut attachments,
|
||||
&mut plays,
|
||||
&mut analyzer,
|
||||
attachment,
|
||||
i,
|
||||
&mut image,
|
||||
&mut grayscale_image,
|
||||
)
|
||||
.await;
|
||||
|
||||
if let Err(err) = result {
|
||||
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)
|
||||
.await?;
|
||||
}
|
||||
// }}}
|
||||
}
|
||||
|
||||
if !embeds.is_empty() {
|
||||
|
|
|
@ -27,6 +27,5 @@ pub fn hash_bytes(bytes: &[u8]) -> String {
|
|||
let mut hasher = Sha256::default();
|
||||
hasher.update(bytes);
|
||||
let res = hasher.finalize();
|
||||
let string = base16ct::lower::encode_string(&res);
|
||||
string
|
||||
base16ct::lower::encode_string(&res)
|
||||
}
|
||||
|
|
|
@ -17,4 +17,3 @@ pub mod recognition;
|
|||
pub mod time;
|
||||
pub mod transform;
|
||||
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