From 3f5ec4f258a92c554eed955230f9f04100b6e387 Mon Sep 17 00:00:00 2001 From: Rafael Bradley Date: Sun, 24 Aug 2025 20:03:52 -0300 Subject: [PATCH] Add colors update --- Cargo.lock | 1076 ++++++++++++++++- Cargo.toml | 7 +- src/colors.rs | 103 ++ src/constants.rs | 2 + .../migrations/0007_add_user_colors.cql | 8 + src/database/models.rs | 59 +- src/discord/images.rs | 21 +- src/framework/bot.rs | 4 +- src/groups/about/embeds.rs | 4 +- src/groups/calls/events.rs | 36 +- .../calls/lists/hate-speech-and-slurs.txt | 1 + src/main.rs | 29 +- src/state.rs | 4 + 13 files changed, 1304 insertions(+), 50 deletions(-) create mode 100644 src/colors.rs create mode 100644 src/database/migrations/0007_add_user_colors.cql diff --git a/Cargo.lock b/Cargo.lock index 5335b95..91affb6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -38,6 +38,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "aligned-vec" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b" +dependencies = [ + "equator", +] + [[package]] name = "alloc-no-stdlib" version = "2.0.4" @@ -124,12 +133,57 @@ dependencies = [ "windows-sys 0.60.2", ] +[[package]] +name = "anyhow" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" + +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" + [[package]] name = "arc-swap" version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" +[[package]] +name = "arg_enum_proc_macro" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "async-compression" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddb939d66e4ae03cee6091612804ba446b12878410cfa17f785f4dd67d4014e8" +dependencies = [ + "brotli", + "flate2", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", + "zstd", + "zstd-safe", +] + [[package]] name = "async-trait" version = "0.1.88" @@ -153,6 +207,29 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "av1-grain" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f3efb2ca85bc610acfa917b5aaa36f3fcbebed5b3182d7f877b02531c4b80c8" +dependencies = [ + "anyhow", + "arrayvec", + "log", + "nom", + "num-rational", + "v_frame", +] + +[[package]] +name = "avif-serialize" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47c8fbc0f831f4519fe8b810b6a7a91410ec83031b8233f730a0480029f6a23f" +dependencies = [ + "arrayvec", +] + [[package]] name = "axum" version = "0.8.4" @@ -228,6 +305,12 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "bit_field" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" + [[package]] name = "bitflags" version = "1.3.2" @@ -240,6 +323,23 @@ version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +[[package]] +name = "bitstream-io" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2" + +[[package]] +name = "brotli" +version = "8.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9991eea70ea4f293524138648e41ee89b0b2b12ddef3b255effa43c8056e0e0d" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor 5.0.0", +] + [[package]] name = "brotli-decompressor" version = "4.0.3" @@ -250,18 +350,46 @@ dependencies = [ "alloc-stdlib", ] +[[package]] +name = "brotli-decompressor" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "built" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ed6191a7e78c36abdb16ab65341eefd73d64d303fffccdbb00d51e4205967b" + [[package]] name = "bumpalo" version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +[[package]] +name = "bytemuck" +version = "1.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677" + [[package]] name = "byteorder" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + [[package]] name = "bytes" version = "1.10.1" @@ -274,6 +402,8 @@ version = "1.2.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3a42d84bb6b69d3a8b3eaacf0d88f179e1929695e1ad012b6cf64d9caaa5fd2" dependencies = [ + "jobserver", + "libc", "shlex", ] @@ -283,6 +413,16 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" +[[package]] +name = "cfg-expr" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" +dependencies = [ + "smallvec", + "target-lexicon", +] + [[package]] name = "cfg-if" version = "1.0.1" @@ -341,6 +481,21 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" +[[package]] +name = "color-thief" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6460d760cf38ce67c9e0318f896538820acc54f2d0a3bfc5b2c557211066c98" +dependencies = [ + "rgb", +] + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + [[package]] name = "colorchoice" version = "1.0.4" @@ -370,6 +525,16 @@ dependencies = [ "tokio-util", ] +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation" version = "0.10.1" @@ -401,12 +566,37 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + [[package]] name = "csv" version = "1.3.1" @@ -539,18 +729,81 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equator" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc" +dependencies = [ + "equator-macro", +] + +[[package]] +name = "equator-macro" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "equivalent" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +[[package]] +name = "errno" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + +[[package]] +name = "exr" +version = "1.73.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83197f59927b46c04a183a619b7c29df34e63e63c7869320862268c0ef687e0" +dependencies = [ + "bit_field", + "half", + "lebe", + "miniz_oxide", + "rayon-core", + "smallvec", + "zune-inflate", +] + [[package]] name = "fastrand" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + [[package]] name = "flate2" version = "1.1.2" @@ -583,6 +836,21 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -715,6 +983,16 @@ dependencies = [ "wasi 0.14.2+wasi-0.2.4", ] +[[package]] +name = "gif" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae047235e33e2829703574b54fdec96bfbad892062d97fed2f76022287de61b" +dependencies = [ + "color_quant", + "weezl", +] + [[package]] name = "gimli" version = "0.31.1" @@ -740,6 +1018,16 @@ dependencies = [ "tracing", ] +[[package]] +name = "half" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" +dependencies = [ + "cfg-if", + "crunchy", +] + [[package]] name = "halfbrown" version = "0.2.5" @@ -873,12 +1161,29 @@ dependencies = [ "tower-service", ] +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + [[package]] name = "hyper-util" version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e" dependencies = [ + "base64", "bytes", "futures-channel", "futures-core", @@ -886,12 +1191,16 @@ dependencies = [ "http", "http-body", "hyper", + "ipnet", "libc", + "percent-encoding", "pin-project-lite", "socket2 0.6.0", + "system-configuration", "tokio", "tower-service", "tracing", + "windows-registry", ] [[package]] @@ -1031,6 +1340,45 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "image" +version = "0.25.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a" +dependencies = [ + "bytemuck", + "byteorder-lite", + "color_quant", + "exr", + "gif", + "image-webp", + "num-traits", + "png", + "qoi", + "ravif", + "rayon", + "rgb", + "tiff", + "zune-core", + "zune-jpeg", +] + +[[package]] +name = "image-webp" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6970fe7a5300b4b42e62c52efa0187540a5bef546c60edaf554ef595d2e6f0b" +dependencies = [ + "byteorder-lite", + "quick-error", +] + +[[package]] +name = "imgref" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408" + [[package]] name = "include_dir" version = "0.7.4" @@ -1080,6 +1428,17 @@ dependencies = [ "libc", ] +[[package]] +name = "interpolate_name" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "io-uring" version = "0.7.9" @@ -1091,6 +1450,22 @@ dependencies = [ "libc", ] +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "iri-string" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "is-docker" version = "0.2.0" @@ -1116,6 +1491,15 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.14.0" @@ -1153,6 +1537,22 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" +[[package]] +name = "jobserver" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +dependencies = [ + "getrandom 0.3.3", + "libc", +] + +[[package]] +name = "jpeg-decoder" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00810f1d8b74be64b13dbf3db89ac67740615d6c891f0e7b6179326533011a07" + [[package]] name = "js-sys" version = "0.3.77" @@ -1183,12 +1583,28 @@ dependencies = [ "libc", ] +[[package]] +name = "lebe" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" + [[package]] name = "libc" version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" +[[package]] +name = "libfuzzer-sys" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5037190e1f70cbeef565bd267599242926f724d3b8a9f510fd7e0b540cfa4404" +dependencies = [ + "arbitrary", + "cc", +] + [[package]] name = "libz-sys" version = "1.1.22" @@ -1209,6 +1625,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "linux-raw-sys" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" + [[package]] name = "litemap" version = "0.8.0" @@ -1234,6 +1656,15 @@ dependencies = [ "serde", ] +[[package]] +name = "loop9" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" +dependencies = [ + "imgref", +] + [[package]] name = "lz4_flex" version = "0.11.5" @@ -1249,6 +1680,16 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" +[[package]] +name = "maybe-rayon" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" +dependencies = [ + "cfg-if", + "rayon", +] + [[package]] name = "memchr" version = "2.7.5" @@ -1271,6 +1712,12 @@ dependencies = [ "unicase", ] +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.8.9" @@ -1278,6 +1725,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", + "simd-adler32", ] [[package]] @@ -1292,6 +1740,45 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "native-tls" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework 2.11.1", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "noop_proc_macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" + [[package]] name = "notify" version = "8.2.0" @@ -1332,6 +1819,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "num-integer" version = "0.1.46" @@ -1341,6 +1839,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -1401,12 +1910,50 @@ dependencies = [ "pathdiff", ] +[[package]] +name = "openssl" +version = "0.10.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" +dependencies = [ + "bitflags 2.9.1", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "openssl-probe" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" +[[package]] +name = "openssl-sys" +version = "0.9.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "ordered-float" version = "2.10.1" @@ -1429,6 +1976,12 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "pathdiff" version = "0.2.3" @@ -1437,25 +1990,30 @@ checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" [[package]] name = "payphone" -version = "4.3.4" +version = "4.3.6" dependencies = [ + "anyhow", "async-trait", "axum", "clap", + "color-thief", "colored", "csv", "deadpool-redis", "dotenvy", + "image", "include_dir", - "itertools", + "itertools 0.14.0", "linkify", "log", "notify", "once_cell", "open", - "rand", - "rand_chacha", + "rand 0.9.2", + "rand_chacha 0.9.0", "regex", + "reqwest", + "rgb", "scc", "scylla", "serde_json", @@ -1497,6 +2055,19 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +[[package]] +name = "png" +version = "0.17.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + [[package]] name = "potential_utf" version = "0.1.2" @@ -1530,6 +2101,40 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "profiling" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773" +dependencies = [ + "profiling-procmacros", +] + +[[package]] +name = "profiling-procmacros" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "qoi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + [[package]] name = "quote" version = "1.0.40" @@ -1545,14 +2150,35 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + [[package]] name = "rand" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ - "rand_chacha", - "rand_core", + "rand_chacha 0.9.0", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", ] [[package]] @@ -1562,7 +2188,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.16", ] [[package]] @@ -1580,7 +2215,77 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b48ac3f7ffaab7fac4d2376632268aa5f89abdb55f7ebf8f4d11fffccb2320f7" dependencies = [ - "rand_core", + "rand_core 0.9.3", +] + +[[package]] +name = "rav1e" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd87ce80a7665b1cce111f8a16c1f3929f6547ce91ade6addf4ec86a8dda5ce9" +dependencies = [ + "arbitrary", + "arg_enum_proc_macro", + "arrayvec", + "av1-grain", + "bitstream-io", + "built", + "cfg-if", + "interpolate_name", + "itertools 0.12.1", + "libc", + "libfuzzer-sys", + "log", + "maybe-rayon", + "new_debug_unreachable", + "noop_proc_macro", + "num-derive", + "num-traits", + "once_cell", + "paste", + "profiling", + "rand 0.8.5", + "rand_chacha 0.3.1", + "simd_helpers", + "system-deps", + "thiserror 1.0.69", + "v_frame", + "wasm-bindgen", +] + +[[package]] +name = "ravif" +version = "0.11.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5825c26fddd16ab9f515930d49028a630efec172e903483c94796cfe31893e6b" +dependencies = [ + "avif-serialize", + "imgref", + "loop9", + "quick-error", + "rav1e", + "rayon", + "rgb", +] + +[[package]] +name = "rayon" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", ] [[package]] @@ -1600,7 +2305,7 @@ dependencies = [ "num-bigint", "percent-encoding", "pin-project-lite", - "rand", + "rand 0.9.2", "ryu", "socket2 0.6.0", "tokio", @@ -1666,6 +2371,58 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "reqwest" +version = "0.12.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d429f34c8092b2d42c7c93cec323bb4adeb7c67698f70839adec842ec10c7ceb" +dependencies = [ + "async-compression", + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-tls", + "hyper-util", + "js-sys", + "log", + "mime", + "native-tls", + "percent-encoding", + "pin-project-lite", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-native-tls", + "tokio-util", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "rgb" +version = "0.8.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c6a884d2998352bb4daf0183589aec883f16a6da1f4dde84d8e2e9a5409a1ce" +dependencies = [ + "bytemuck", +] + [[package]] name = "ring" version = "0.17.14" @@ -1686,6 +2443,19 @@ version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" +[[package]] +name = "rustix" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" +dependencies = [ + "bitflags 2.9.1", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.60.2", +] + [[package]] name = "rustls" version = "0.23.31" @@ -1709,7 +2479,7 @@ dependencies = [ "openssl-probe", "rustls-pki-types", "schannel", - "security-framework", + "security-framework 3.2.0", ] [[package]] @@ -1727,7 +2497,7 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19787cda76408ec5404443dc8b31795c87cd8fec49762dc75fa727740d34acc1" dependencies = [ - "core-foundation", + "core-foundation 0.10.1", "core-foundation-sys", "jni", "log", @@ -1736,7 +2506,7 @@ dependencies = [ "rustls-native-certs", "rustls-platform-verifier-android", "rustls-webpki", - "security-framework", + "security-framework 3.2.0", "security-framework-sys", "webpki-root-certs 0.26.11", "windows-sys 0.59.0", @@ -1748,7 +2518,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be59af91596cac372a6942530653ad0c3a246cdd491aaa9dcaee47f88d67d5a0" dependencies = [ - "core-foundation", + "core-foundation 0.10.1", "core-foundation-sys", "jni", "log", @@ -1757,7 +2527,7 @@ dependencies = [ "rustls-native-certs", "rustls-platform-verifier-android", "rustls-webpki", - "security-framework", + "security-framework 3.2.0", "security-framework-sys", "webpki-root-certs 1.0.2", "windows-sys 0.59.0", @@ -1838,8 +2608,8 @@ dependencies = [ "dashmap", "futures", "hashbrown 0.15.4", - "itertools", - "rand", + "itertools 0.14.0", + "rand 0.9.2", "rand_pcg", "scylla-cql", "smallvec", @@ -1859,7 +2629,7 @@ dependencies = [ "byteorder", "bytes", "chrono", - "itertools", + "itertools 0.14.0", "lz4_flex", "scylla-macros", "snap", @@ -1889,6 +2659,19 @@ version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "490dcfcbfef26be6800d11870ff2df8774fa6e86d047e3e8c8a76b25655e41ca" +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.9.1", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + [[package]] name = "security-framework" version = "3.2.0" @@ -1896,7 +2679,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" dependencies = [ "bitflags 2.9.1", - "core-foundation", + "core-foundation 0.10.1", "core-foundation-sys", "libc", "security-framework-sys", @@ -1975,6 +2758,15 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -1999,6 +2791,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + [[package]] name = "simd-json" version = "0.14.3" @@ -2014,6 +2812,15 @@ dependencies = [ "value-trait", ] +[[package]] +name = "simd_helpers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" +dependencies = [ + "quote", +] + [[package]] name = "simdutf8" version = "0.1.5" @@ -2092,6 +2899,9 @@ name = "sync_wrapper" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] [[package]] name = "synstructure" @@ -2104,6 +2914,59 @@ dependencies = [ "syn", ] +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags 2.9.1", + "core-foundation 0.9.4", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "system-deps" +version = "6.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" +dependencies = [ + "cfg-expr", + "heck", + "pkg-config", + "toml", + "version-compare", +] + +[[package]] +name = "target-lexicon" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + +[[package]] +name = "tempfile" +version = "3.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15b61f8f20e3a6f7e0649d825294eaf317edce30f82cf6026e7e4cb9222a7d1e" +dependencies = [ + "fastrand", + "getrandom 0.3.3", + "once_cell", + "rustix", + "windows-sys 0.60.2", +] + [[package]] name = "thiserror" version = "1.0.69" @@ -2144,6 +3007,17 @@ dependencies = [ "syn", ] +[[package]] +name = "tiff" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" +dependencies = [ + "flate2", + "jpeg-decoder", + "weezl", +] + [[package]] name = "time" version = "0.3.41" @@ -2216,6 +3090,16 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.26.2" @@ -2262,6 +3146,40 @@ dependencies = [ "tokio-util", ] +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "tower" version = "0.5.2" @@ -2293,12 +3211,14 @@ dependencies = [ "http-body-util", "http-range-header", "httpdate", + "iri-string", "mime", "mime_guess", "percent-encoding", "pin-project-lite", "tokio", "tokio-util", + "tower", "tower-layer", "tower-service", "tracing", @@ -2404,7 +3324,7 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af9a2176638fd8bfeb867e7a2f644fee0db905eba6f7decfdcd75c8171109b74" dependencies = [ - "brotli-decompressor", + "brotli-decompressor 4.0.3", "fastrand", "http", "http-body-util", @@ -2535,6 +3455,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "v_frame" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "666b7727c8875d6ab5db9533418d7c764233ac9c0cff1d469aec8fa127597be2" +dependencies = [ + "aligned-vec", + "num-traits", + "wasm-bindgen", +] + [[package]] name = "value-trait" version = "0.10.1" @@ -2553,6 +3484,12 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "version-compare" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" + [[package]] name = "version_check" version = "0.9.5" @@ -2619,6 +3556,19 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.100" @@ -2651,6 +3601,16 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "web-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "webpki-root-certs" version = "0.26.11" @@ -2669,6 +3629,12 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "weezl" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3" + [[package]] name = "winapi-util" version = "0.1.9" @@ -2719,6 +3685,17 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" +[[package]] +name = "windows-registry" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e" +dependencies = [ + "windows-link", + "windows-result", + "windows-strings", +] + [[package]] name = "windows-result" version = "0.3.4" @@ -2959,6 +3936,15 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" +[[package]] +name = "winnow" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +dependencies = [ + "memchr", +] + [[package]] name = "wit-bindgen-rt" version = "0.39.0" @@ -3077,3 +4063,55 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.15+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237" +dependencies = [ + "cc", + "pkg-config", +] + +[[package]] +name = "zune-core" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" + +[[package]] +name = "zune-inflate" +version = "0.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "zune-jpeg" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1f7e205ce79eb2da3cd71c5f55f3589785cb7c79f6a03d1c8d1491bda5d089" +dependencies = [ + "zune-core", +] diff --git a/Cargo.toml b/Cargo.toml index 8696572..501a019 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,17 +1,20 @@ [package] name = "payphone" -version = "4.3.4" +version = "4.3.6" edition = "2024" default-run = "payphone" [dependencies] +anyhow = "1.0.99" async-trait = "0.1.88" axum = "0.8.4" clap = { version = "4.5.42", features = ["derive", "env", "string"] } +color-thief = "0.2.2" colored = "3.0.0" csv = "1.3.1" deadpool-redis = { version = "0.22.0", features = ["cluster", "cluster-async"] } dotenvy = "0.15.7" +image = "0.25.6" include_dir = "0.7.4" itertools = "0.14.0" linkify = "0.10.0" @@ -22,6 +25,8 @@ open = "5.3.2" rand = "0.9.2" rand_chacha = { version = "0.9.0", features = ["os_rng"] } regex = "1.11.1" +reqwest = { version = "0.12.23", features = ["gzip", "brotli", "zstd"] } +rgb = "0.8.52" scc = "2.3.4" scylla = { version = "1.3.1", features = ["time-03"] } serde_json = "1.0.143" diff --git a/src/colors.rs b/src/colors.rs new file mode 100644 index 0000000..ceb176a --- /dev/null +++ b/src/colors.rs @@ -0,0 +1,103 @@ +use std::{io::Cursor, sync::Arc}; + +use color_thief::ColorFormat; +use image::{GenericImageView, ImageReader}; +use reqwest::header::USER_AGENT; +use rgb::Rgb; +use tokio::sync::{Semaphore, mpsc::Receiver}; + +use crate::{ + constants::VERSION, database::models::User, + discord::images::get_user_custom_avatar_url_or_none, state::State, +}; + +pub struct AvatarColorFetchingRequest { + pub hash: String, + pub user_id: u64, +} + +impl AvatarColorFetchingRequest { + pub fn new(hash: impl ToString, user_id: u64) -> Self { + Self { + hash: hash.to_string(), + user_id, + } + } +} + +pub fn init_color_fetching_queue_listener( + mut receiver: Receiver, + state: Arc, +) { + tokio::spawn(async move { + let semaphore = Arc::new(Semaphore::new(5)); + + while let Some(request) = receiver.recv().await { + let task_semaphore = semaphore.clone(); + let task_state = state.clone(); + + tokio::spawn(async move { + let _permit = task_semaphore + .acquire() + .await + .inspect_err(|e| log::error!("Failed to acquire semaphore permit: {e}")) + .expect("Failed to acquire semaphore permit"); + + let avatar_url = get_user_custom_avatar_url_or_none(request.user_id, request.hash); + + let image_bytes = reqwest::Client::new() + .get(avatar_url) + .header(USER_AGENT, format!("Payphone/v{VERSION}")) + .send() + .await + .inspect_err(|e| log::error!("Failed to fetch avatar color: {e}"))? + .error_for_status()? + .bytes() + .await + .inspect_err(|e| log::error!("Failed to read avatar image bytes: {e}"))?; + + let color = tokio::task::spawn_blocking(move || { + let img = ImageReader::new(Cursor::new(image_bytes)) + .with_guessed_format()? + .decode()?; + + let mut pixels = Vec::new(); + + for (_x, _y, rgba) in img.pixels() { + pixels.extend_from_slice(&rgba.0); + } + + drop(img); + + let palette = color_thief::get_palette(&pixels, ColorFormat::Rgba, 1, 2)?; + + Ok::<_, anyhow::Error>(palette.first().cloned()) + }) + .await??; + + if let Some(color) = color { + let Rgb { r, g, b } = color; + + let color_int: u32 = ((r as u32) << 16) | ((g as u32) << 8) | (b as u32); + + let mut user = User::get_by_id(request.user_id, &task_state.db) + .await + .inspect_err(|e| { + log::error!("Failed to fetch user to set their new avatar color: {e}") + })? + .ok_or(anyhow::anyhow!( + "User with ID {} not found when fetching their avatar URL color", + request.user_id + )) + .inspect_err(|e| log::error!("{e}"))?; + + user.color = Some(color_int as i32); + + user.insert(&task_state.db).await?; + } + + Ok::<_, anyhow::Error>(()) + }); + } + }); +} diff --git a/src/constants.rs b/src/constants.rs index 55ff8ca..f6a39ba 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -1,5 +1,7 @@ //! Constants used throughout the Payphone project. +pub const VERSION: &str = env!("CARGO_PKG_VERSION"); + /// The default command prefix used by the bot for new servers. pub const DEFAULT_PREFIX: &str = "p."; diff --git a/src/database/migrations/0007_add_user_colors.cql b/src/database/migrations/0007_add_user_colors.cql new file mode 100644 index 0000000..bb3f20b --- /dev/null +++ b/src/database/migrations/0007_add_user_colors.cql @@ -0,0 +1,8 @@ +ALTER TABLE payphone.users ADD avatar_hash TEXT; +ALTER TABLE payphone.users ADD color INT; +ALTER TABLE payphone.users ADD is_color_set BOOLEAN; + +CREATE MATERIALIZED VIEW payphone.users_with_no_color AS + SELECT user_id, avatar_hash, is_color_set FROM payphone.users + WHERE user_id IS NOT NULL AND is_color_set IS NOT NULL + PRIMARY KEY (is_color_set, user_id); diff --git a/src/database/models.rs b/src/database/models.rs index 0a2e37d..75a5d26 100644 --- a/src/database/models.rs +++ b/src/database/models.rs @@ -16,6 +16,7 @@ use scylla::{ }; use thiserror::Error; use time::{Duration, OffsetDateTime, UtcDateTime, UtcOffset}; +use tokio::sync::mpsc::Sender; use twilight_http::Client; use twilight_model::{ channel::{Message as TwilightMessage, Webhook}, @@ -25,9 +26,10 @@ use twilight_model::{ }; use crate::{ + colors::AvatarColorFetchingRequest, constants::DEFAULT_PREFIX, groups::calls::masks::{get_mask_avatar_url, get_mask_display_name, get_random_mask}, - utils::{get_random_u64, i64_to_u64, u64_to_i64}, + utils::{Bye, get_random_u64, i64_to_u64, u64_to_i64}, }; #[derive(Debug, Error)] @@ -105,6 +107,8 @@ pub struct User { pub supporter_until: Option, pub is_banned_from_leaderboard: Option, pub findings: HashSet, + pub avatar_hash: Option, + pub color: Option, } impl<'a> Object<'a> for User { @@ -120,6 +124,9 @@ impl<'a> Object<'a> for User { Option, Option, HashSet, + Option, + Option, + Option, ); fn from_row(row: Self::Row) -> Self { @@ -135,6 +142,8 @@ impl<'a> Object<'a> for User { supporter_until: row.8.map(|i| i.into()), is_banned_from_leaderboard: row.9, findings: row.10, + avatar_hash: row.11, + color: row.12, } } @@ -151,6 +160,9 @@ impl<'a> Object<'a> for User { value.supporter_until.map(|i| i.into()), Some(value.is_banned_from_leaderboard.unwrap_or(false)), value.findings, + value.avatar_hash, + value.color, + Some(value.color.is_some()), ) } } @@ -178,7 +190,10 @@ impl User { supporter_since, supporter_until, is_banned_from_leaderboard, - findings + findings, + avatar_hash, + color, + is_color_set FROM payphone.users WHERE @@ -218,6 +233,7 @@ impl User { pub async fn create_or_update( user: TwilightUser, session: &Session, + sender: &Sender, ) -> Result { let db_user = User::get_by_id(user.id.get(), session).await?; @@ -225,10 +241,38 @@ impl User { db_user.last_seen_at = UtcDateTime::now(); db_user.name = user.name; + if user.avatar.map(|hash| hash.to_string()) != db_user.avatar_hash { + db_user.avatar_hash = user.avatar.map(|hash| hash.to_string()); + db_user.color = None; + + if let Some(avatar_hash) = &db_user.avatar_hash { + sender + .send(AvatarColorFetchingRequest::new(avatar_hash, user.id.get())) + .await + .inspect_err(|e| { + log::error!( + "Failed to send avatar color fetching request to queue! {e}" + ) + }) + .bye(); + } + } + return Ok(db_user); } let new_user = User::from(user); + + if let Some(avatar_hash) = &new_user.avatar_hash { + sender + .send(AvatarColorFetchingRequest::new(avatar_hash, new_user.id)) + .await + .inspect_err(|e| { + log::error!("Failed to send avatar color fetching request to queue! {e}") + }) + .bye(); + } + new_user.insert(session).await?; Ok(new_user) @@ -249,8 +293,11 @@ impl User { supporter_since, supporter_until, is_banned_from_leaderboard, - findings - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + findings, + avatar_hash, + color, + is_color_set + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); "#, Self::to_row(self.clone()), ) @@ -338,6 +385,8 @@ impl From for User { supporter_until: None, is_banned_from_leaderboard: None, findings: HashSet::new(), + avatar_hash: value.avatar.map(|a| a.to_string()), + color: None, } } } @@ -1865,7 +1914,7 @@ impl<'a> Object<'a> for Participant { fn make_name_valid(name: String) -> String { if name.len() == 1 { - format!("{name}\u{2800}") + format!("{name}⠀⠀") // Add two invisible characters } else if name.len() > 80 { format!("{name:.80}") } else { diff --git a/src/discord/images.rs b/src/discord/images.rs index 11307dc..f47b59d 100644 --- a/src/discord/images.rs +++ b/src/discord/images.rs @@ -13,10 +13,17 @@ use twilight_model::util::ImageHash; /// /// Returns: /// [`String`] - The URL of the user's avatar. -pub fn get_avatar_url(hash: Option, user_id: u64, discriminator: u64, guild_id: Option) -> String { +pub fn get_avatar_url( + hash: Option, + user_id: u64, + discriminator: u64, + guild_id: Option, +) -> String { if let Some(hash) = hash { if let Some(guild_id) = guild_id { - return format!("https://cdn.discordapp.com/guilds/{guild_id}/users/{user_id}/avatars/{hash}.webp?size=256"); + return format!( + "https://cdn.discordapp.com/guilds/{guild_id}/users/{user_id}/avatars/{hash}.webp?size=256" + ); } format!("https://cdn.discordapp.com/avatars/{user_id}/{hash}.webp?size=256") @@ -30,3 +37,13 @@ pub fn get_avatar_url(hash: Option, user_id: u64, discriminator: u64, ) } } + +/// Returns the user's avatar URL only if it's custom (i.e. not the default avatar). It doesn't +/// take into account custom per-server avatars, i.e. only the global avatar is returned if any. +/// +/// Arguments: +/// * `user_id` - The user's ID. +/// * `hash` - The hex-encoded hash string, if any. +pub fn get_user_custom_avatar_url_or_none(user_id: u64, hash: String) -> String { + format!("https://cdn.discordapp.com/avatars/{user_id}/{hash}.webp?size=256") +} diff --git a/src/framework/bot.rs b/src/framework/bot.rs index 0807ed4..f0cf459 100644 --- a/src/framework/bot.rs +++ b/src/framework/bot.rs @@ -119,13 +119,13 @@ where E: 'static + Send + Sync, { pub fn new( - state: T, + state: Arc, prefixes: impl PrefixGetter + Send + Sync + 'static, extras: impl ExtrasGetter + 'static, ) -> Self { Self { shard: ShardId::new(0, 1), - state: Arc::new(state), + state, presence: None, prefixes: Arc::new(prefixes), intents: Intents::empty(), diff --git a/src/groups/about/embeds.rs b/src/groups/about/embeds.rs index ea8cc3c..49163dd 100644 --- a/src/groups/about/embeds.rs +++ b/src/groups/about/embeds.rs @@ -6,7 +6,7 @@ use twilight_util::builder::embed::{ }; use crate::{ - constants::{COLOR_RED, COLOR_WHITE}, + constants::{COLOR_RED, COLOR_WHITE, VERSION}, discord::{images, sanitizing::SanitizeDiscordMarkdown}, extras::Extras, framework::{ @@ -106,7 +106,7 @@ pub(super) fn get_all_command_help_embed( .unwrap()) .color(COLOR_WHITE) .field(EmbedFieldBuilder::new("Commands", get_commands_table(rt, extras)).build()) - .footer(EmbedFooterBuilder::new(format!("v{} - Use {}help to get more information about a specific command.", env!("CARGO_PKG_VERSION"), prefix))) + .footer(EmbedFooterBuilder::new(format!("v{VERSION} - Use {}help to get more information about a specific command.", prefix))) .build() } diff --git a/src/groups/calls/events.rs b/src/groups/calls/events.rs index 62c0734..5f0779d 100644 --- a/src/groups/calls/events.rs +++ b/src/groups/calls/events.rs @@ -6,7 +6,6 @@ use time::{Duration, UtcDateTime}; use twilight_http::{api_error::ApiError, error::ErrorType}; use twilight_model::{ gateway::payload::incoming::{MessageCreate, MessageDelete, MessageUpdate}, - guild, id::Id, }; use twilight_util::{ @@ -165,7 +164,12 @@ impl OnMessageHandler for CallMessageHandler { return Ok(()); }; - let mut user = User::create_or_update(event.author.clone(), &rt.state.db).await?; + let mut user = User::create_or_update( + event.author.clone(), + &rt.state.db, + &rt.state.color_queue_sender, + ) + .await?; let user_incidents = UserIncident::get_for_user(event.author.id.get(), &rt.state.db) .await? @@ -307,18 +311,18 @@ impl OnMessageHandler for CallMessageHandler { .zip(replying_to.data.propagation_message_id) { let (display_name, avatar_url) = - if let Some(mask) = replying_to.data.author_mask { + if let Some(mask) = &replying_to.data.author_mask { ( if i64_to_u64(propagation_channel_id) != event.channel_id.get() { - get_mask_display_name(&mask) + get_mask_display_name(mask) } else { format!( "{} ({})", - get_mask_display_name(&mask), + get_mask_display_name(mask), replying_to.data.author_name ) }, - get_mask_avatar_url(&mask).expect("Failed to get mask avatar URL"), + get_mask_avatar_url(mask).expect("Failed to get mask avatar URL"), ) } else { ( @@ -339,6 +343,9 @@ impl OnMessageHandler for CallMessageHandler { ) }; + let replying_to_user = + User::get_by_id(replying_to.author_id, &rt.state.db).await?; + embeds.push( EmbedBuilder::new() .author( @@ -346,7 +353,15 @@ impl OnMessageHandler for CallMessageHandler { .icon_url(ImageSource::url(avatar_url).unwrap()) .url(message_link), ) - .color(COLOR_WHITE) + .color( + if replying_to.data.author_mask.is_some() { + COLOR_WHITE + } else { + replying_to_user + .and_then(|i| i.color.map(|c| c as u32)) + .unwrap_or(COLOR_WHITE) + } + ) .description(ellipse(replying_to.data.content, 100)) .build(), ); @@ -508,7 +523,12 @@ impl OnMessageEditHandler for CallMessageEditHandler { .reply(event.id) .await?; - let user = User::create_or_update(event.author.clone(), &rt.state.db).await?; + let user = User::create_or_update( + event.author.clone(), + &rt.state.db, + &rt.state.color_queue_sender, + ) + .await?; penalize_user(user, message, rules, &rt).await?; diff --git a/src/groups/calls/lists/hate-speech-and-slurs.txt b/src/groups/calls/lists/hate-speech-and-slurs.txt index 9a44d29..e9e7651 100644 --- a/src/groups/calls/lists/hate-speech-and-slurs.txt +++ b/src/groups/calls/lists/hate-speech-and-slurs.txt @@ -22,6 +22,7 @@ ngiga ngigas negaras nigy +nyga diga digas fag diff --git a/src/main.rs b/src/main.rs index c88c082..257b5f2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -105,7 +105,7 @@ use std::{ net::{IpAddr, Ipv4Addr, SocketAddr}, path::Path, process::Command, - sync::mpsc, + sync::Arc, }; use async_trait::async_trait; @@ -126,7 +126,8 @@ use twilight_model::{ use crate::{ cli::{Args, Commands}, - constants::DEFAULT_PREFIX, + colors::init_color_fetching_queue_listener, + constants::{DEFAULT_PREFIX, VERSION}, database::models::{Server, User}, extras::Extras, framework::{ @@ -137,7 +138,9 @@ use crate::{ groups::{ about::{commands::HelpCommand, components::HelpGoBackButton}, calls::{ - commands::{CallCommand, FriendRequestCommand, HangupCommand, MaskCommand, SkipCommand}, + commands::{ + CallCommand, FriendRequestCommand, HangupCommand, MaskCommand, SkipCommand, + }, events::{CallMessageDeleteHandler, CallMessageEditHandler, CallMessageHandler}, }, gateway::events::{ReadyHandler, ReconnectHandler}, @@ -152,6 +155,7 @@ use crate::{ }; mod cli; +mod colors; mod constants; mod database; mod discord; @@ -241,7 +245,8 @@ impl ExtrasGetter for PayphoneExtrasGetter { ) -> Result> { log::trace!("Getting extras!"); - let user = User::create_or_update(user.clone(), &rt.state.db).await?; + let user = User::create_or_update(user.clone(), &rt.state.db, &rt.state.color_queue_sender) + .await?; Ok(Extras { user }) } @@ -258,10 +263,7 @@ async fn start( bot_owner_id: u64, ) { log::info!("Welcome to Payphone, Nyeki!"); - log::info!( - "Payphone is running on version v{}", - env!("CARGO_PKG_VERSION") - ); + log::info!("Payphone is running on version v{VERSION}"); let db = database::init(database_addr, database_username, database_password) .await @@ -273,11 +275,16 @@ async fn start( log::info!("Redis connection established successfully."); - let state = State { + let (color_queue_sender, color_queue_receiver) = tokio::sync::mpsc::channel(100); + + let state = Arc::new(State { db, redis: redis_pool, bot_owner_id, - }; + color_queue_sender, + }); + + init_color_fetching_queue_listener(color_queue_receiver, state.clone()); let bot = Bot::new(state, ServerPrefixOrPayphoneMention, PayphoneExtrasGetter) .shard(shard) @@ -352,7 +359,7 @@ async fn docs(bind: SocketAddr, open_on_start: bool) { .expect("Failed to run `cargo doc`"); tokio::spawn(async { - let (tx, rx) = mpsc::channel::>(); + let (tx, rx) = std::sync::mpsc::channel::>(); let mut watcher = notify::recommended_watcher(tx).expect("Failed to create watcher"); diff --git a/src/state.rs b/src/state.rs index d80a015..934482d 100644 --- a/src/state.rs +++ b/src/state.rs @@ -20,9 +20,13 @@ use deadpool_redis::cluster::Pool; use scylla::client::session::Session; +use tokio::sync::mpsc::Sender; + +use crate::colors::AvatarColorFetchingRequest; pub struct State { pub db: Session, pub redis: Pool, pub bot_owner_id: u64, + pub color_queue_sender: Sender, }