Compare commits

...

10 commits

Author SHA1 Message Date
Tom 7872513949 Fix WRC url
also set it to own site so no need for bot updates if the url format ever changes.
2023-04-21 21:31:50 +02:00
Tom 1db9ebdde2 Fix command descriptions
(needs tripple /// not double)
And clean up some commented out code.
Also update caches for viaplay to make a bit more sense
2023-04-09 21:03:50 +02:00
Tom df60ac6aae Add viaplay_schedule command to get schedule for specific day
Clean up some comments of dead/old code
2023-04-09 14:19:26 +02:00
Tom 5d2f9a777c To be || not to be 2023-04-08 20:58:55 +02:00
Tom fff7611e9b Cargo fmt
And fix pagination for ephemeral commands
2023-04-08 20:41:04 +02:00
Tom 8d8662be75 Add default_register command
This will make registering the default setup easier
2023-04-08 20:40:09 +02:00
Tom 86cc799988 Remove old db file 2023-04-07 19:08:29 +02:00
Tom 5caf820dc0 Update poise version (with refactor)
set some command to ephemeral
Add roles command
Do some refactoring and minor changes to commands
2023-04-07 19:06:14 +02:00
Tom 12b934fcb4 Add all and cmore commands. And some small updates to others to integrate better for all 2022-11-28 12:31:17 +01:00
Tom 8ac7702d8c Add NFL links 2022-09-11 22:41:01 +02:00
19 changed files with 1207 additions and 348 deletions

232
Cargo.lock generated
View file

@ -165,16 +165,16 @@ checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db"
[[package]]
name = "cached"
version = "0.38.0"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27e6092f8c7ba6e65a46f6f26d7d7997201d3a6f0e69ff5d2440b930d7c0513a"
checksum = "5e5877db5d1af7fae60d06b5db9430b68056a69b3582a0be8e3691e87654aeb6"
dependencies = [
"async-trait",
"async_once",
"cached_proc_macro",
"cached_proc_macro_types",
"futures",
"hashbrown",
"hashbrown 0.13.2",
"instant",
"lazy_static",
"once_cell",
@ -184,12 +184,13 @@ dependencies = [
[[package]]
name = "cached_proc_macro"
version = "0.15.0"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "751f7f4e7a091545e7f6c65bacc404eaee7e87bfb1f9ece234a1caa173dc16f2"
checksum = "e10ca87c81aaa3a949dbbe2b5e6c2c45dbc94ba4897e45ea31ff9ec5087be3dc"
dependencies = [
"cached_proc_macro_types",
"darling 0.13.4",
"darling",
"proc-macro2",
"quote",
"syn",
]
@ -391,43 +392,19 @@ dependencies = [
[[package]]
name = "darling"
version = "0.13.4"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c"
checksum = "c0808e1bd8671fb44a113a14e13497557533369847788fa2ae912b6ebfce9fa8"
dependencies = [
"darling_core 0.13.4",
"darling_macro 0.13.4",
]
[[package]]
name = "darling"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4529658bdda7fd6769b8614be250cdcfc3aeb0ee72fe66f9e41e5e5eb73eac02"
dependencies = [
"darling_core 0.14.1",
"darling_macro 0.14.1",
"darling_core",
"darling_macro",
]
[[package]]
name = "darling_core"
version = "0.13.4"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"strsim",
"syn",
]
[[package]]
name = "darling_core"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "649c91bc01e8b1eac09fb91e8dbc7d517684ca6be8ebc75bb9cafc894f9fdb6f"
checksum = "001d80444f28e193f30c2f293455da62dcf9a6b29918a4253152ae2b1de592cb"
dependencies = [
"fnv",
"ident_case",
@ -439,22 +416,11 @@ dependencies = [
[[package]]
name = "darling_macro"
version = "0.13.4"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"
checksum = "b36230598a2d5de7ec1c6f51f72d8a99a9208daff41de2084d06e3fd3ea56685"
dependencies = [
"darling_core 0.13.4",
"quote",
"syn",
]
[[package]]
name = "darling_macro"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddfc69c5bfcbd2fc09a0f38451d2daf0e372e367986a83906d1b0dbc88134fb5"
dependencies = [
"darling_core 0.14.1",
"darling_core",
"quote",
"syn",
]
@ -466,7 +432,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3495912c9c1ccf2e18976439f4443f3fee0fd61f424ff99fde6a66b15ecb448f"
dependencies = [
"cfg-if",
"hashbrown",
"hashbrown 0.12.3",
"lock_api",
"parking_lot_core",
"serde",
@ -761,6 +727,12 @@ dependencies = [
"ahash",
]
[[package]]
name = "hashbrown"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
[[package]]
name = "hermit-abi"
version = "0.1.19"
@ -891,7 +863,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
dependencies = [
"autocfg",
"hashbrown",
"hashbrown 0.12.3",
]
[[package]]
@ -1074,11 +1046,11 @@ dependencies = [
[[package]]
name = "lru"
version = "0.7.8"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e999beba7b6e8345721bd280141ed958096a2e4abdf74f67ff4ce49b4b54e47a"
checksum = "b6e8aaa3f231bb4bd57b84b2d5dc3ae7f350265df8aa96492e0bc394a1571909"
dependencies = [
"hashbrown",
"hashbrown 0.12.3",
]
[[package]]
@ -1142,14 +1114,14 @@ dependencies = [
"libc",
"log",
"wasi 0.11.0+wasi-snapshot-preview1",
"windows-sys",
"windows-sys 0.36.1",
]
[[package]]
name = "mysql_async"
version = "0.30.0"
version = "0.31.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "456207bb9636a0fdade67a64cea7bdebe6730c3c16ee5e34f2c481838ee5a39e"
checksum = "2975442c70450b8f3a0400216321f6ab7b8bda177579f533d312ac511f913655"
dependencies = [
"bytes",
"crossbeam",
@ -1166,6 +1138,7 @@ dependencies = [
"pem",
"percent-encoding",
"pin-project",
"priority-queue",
"serde",
"serde_json",
"socket2",
@ -1179,9 +1152,9 @@ dependencies = [
[[package]]
name = "mysql_common"
version = "0.29.1"
version = "0.29.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "522f2f30f72de409fc04f88df25a031f98cfc5c398a94e0b892cabb33a1464cb"
checksum = "9006c95034ccf7b903d955f210469119f6c3477fc9c9e7a7845ce38a3e665c2a"
dependencies = [
"base64",
"bigdecimal",
@ -1205,7 +1178,7 @@ dependencies = [
"saturating",
"serde",
"serde_json",
"sha-1",
"sha1",
"sha2",
"smallvec",
"subprocess",
@ -1380,7 +1353,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccd746e37177e1711c20dd619a1620f34f5c8b569c53590a72dedd5344d8924a"
dependencies = [
"dlv-list",
"hashbrown",
"hashbrown 0.12.3",
]
[[package]]
@ -1403,7 +1376,7 @@ dependencies = [
"libc",
"redox_syscall",
"smallvec",
"windows-sys",
"windows-sys 0.36.1",
]
[[package]]
@ -1517,9 +1490,9 @@ checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
[[package]]
name = "poise"
version = "0.3.0"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6c01d22dcda434b0dfe956c60f6ac9b0352c4c2f4af852afb3155a971cd306d"
checksum = "2ca787e4e516076de1995a83ee05fbdfed71d072ea0da3df018318db42a87803"
dependencies = [
"async-trait",
"derivative",
@ -1536,11 +1509,11 @@ dependencies = [
[[package]]
name = "poise_macros"
version = "0.3.0"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52ff861b6a52ec47bc54eb17424c025feeb040e82836036276c25dda045a8a0c"
checksum = "b80c1f4e04114527f9d41ed6bb31707a095276f51bb0aef3ca11f062b25a67c4"
dependencies = [
"darling 0.14.1",
"darling",
"proc-macro2",
"quote",
"syn",
@ -1552,6 +1525,16 @@ version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
[[package]]
name = "priority-queue"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ca9c6be70d989d21a136eb86c2d83e4b328447fac4a88dace2143c179c86267"
dependencies = [
"autocfg",
"indexmap",
]
[[package]]
name = "proc-macro-hack"
version = "0.5.19"
@ -1560,9 +1543,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
[[package]]
name = "proc-macro2"
version = "1.0.43"
version = "1.0.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab"
checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6"
dependencies = [
"unicode-ident",
]
@ -1790,7 +1773,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2"
dependencies = [
"lazy_static",
"windows-sys",
"windows-sys 0.36.1",
]
[[package]]
@ -1928,6 +1911,17 @@ dependencies = [
"digest",
]
[[package]]
name = "sha1"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "006769ba83e921b3085caa8334186b00cf92b4cb1a6cf4632fbccc8eff5c7549"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "sha2"
version = "0.10.2"
@ -1956,13 +1950,13 @@ dependencies = [
[[package]]
name = "simplelog"
version = "0.11.2"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1348164456f72ca0116e4538bdaabb0ddb622c7d9f16387c725af3e96d6001c"
checksum = "48dfff04aade74dd495b007c831cd6f4e0cee19c344dd9dc0884c0289b70a786"
dependencies = [
"chrono",
"log",
"termcolor",
"time 0.3.13",
]
[[package]]
@ -2099,8 +2093,15 @@ dependencies = [
"libc",
"num_threads",
"serde",
"time-macros",
]
[[package]]
name = "time-macros"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792"
[[package]]
name = "tinyvec"
version = "1.6.0"
@ -2118,9 +2119,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "tokio"
version = "1.20.1"
version = "1.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a8325f63a7d4774dd041e363b2409ed1c5cbbd0f867795e661df066b2b0a581"
checksum = "03201d01c3c27a29c8a5cee5b55a93ddae1ccf6f08f65365c2c918f8c1b76f64"
dependencies = [
"autocfg",
"bytes",
@ -2128,12 +2129,11 @@ dependencies = [
"memchr",
"mio",
"num_cpus",
"once_cell",
"pin-project-lite",
"signal-hook-registry",
"socket2",
"tokio-macros",
"winapi",
"windows-sys 0.45.0",
]
[[package]]
@ -2513,43 +2513,109 @@ version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
dependencies = [
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_msvc",
"windows_aarch64_msvc 0.36.1",
"windows_i686_gnu 0.36.1",
"windows_i686_msvc 0.36.1",
"windows_x86_64_gnu 0.36.1",
"windows_x86_64_msvc 0.36.1",
]
[[package]]
name = "windows-sys"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc 0.42.1",
"windows_i686_gnu 0.42.1",
"windows_i686_msvc 0.42.1",
"windows_x86_64_gnu 0.42.1",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc 0.42.1",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
[[package]]
name = "windows_aarch64_msvc"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
[[package]]
name = "windows_i686_gnu"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
[[package]]
name = "windows_i686_gnu"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
[[package]]
name = "windows_i686_msvc"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
[[package]]
name = "windows_i686_msvc"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
[[package]]
name = "windows_x86_64_gnu"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
[[package]]
name = "windows_x86_64_msvc"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
[[package]]
name = "winreg"
version = "0.10.1"

View file

@ -6,16 +6,16 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
cached = "0.38"
cached = "0.42"
chrono = "0.4"
config = "0.13"
futures = { version = "0.3", default-features = false }
glob = "0.3"
lazy_static = "1"
log = "0.4"
mysql_async = "0.30"
simplelog = "0.11.1"
poise = { version = "0.3", features = ["collector"] }
mysql_async = "0.31"
simplelog = "0.12"
poise = { version = "0.5", features = ["collector"] }
rand = "0.8"
regex = {version="1"}
reqwest = "0.11"

Binary file not shown.

View file

@ -9,8 +9,6 @@ async fn autocomplete_command<'a>(ctx: Context<'_>, partial: &'a str) -> Vec<Str
};
let stmt = conn.prep("SELECT sign FROM commands WHERE sign LIKE CONCAT('%', :partial, '%') AND enabled ORDER BY priority DESC, sign ASC LIMIT 25").await.unwrap();
// let ding = con.exec(&stmt, params! {partial}).await?;
// let iter = ding.into_iter().map(|a| a.to_string());
let result = match conn.exec_iter(stmt, params! {partial}).await {
Ok(blah) => blah
.map_and_drop(|row| from_row::<String>(row))
@ -29,7 +27,7 @@ pub async fn get_command(sign: &str, con: &mut Conn) -> Result<Option<String>, m
Ok(a)
}
// F1TV links throughout the seasons
/// Run any of a collection of arbitrary commands
#[poise::command(slash_command)]
pub async fn coms(
ctx: Context<'_>,
@ -74,11 +72,11 @@ fn sky(input: &str) -> String {
fn sky_open(input: &str) -> Option<(String, String)> {
match input.rsplit_once('{') {
None => (return None),
None => return None,
Some((left, end)) => {
if left.ends_with('\\') {
match sky_open(left) {
None => (return None),
None => return None,
Some((left, right)) => {
let mut end: String = end.to_string();
end.push('{');
@ -95,11 +93,11 @@ fn sky_open(input: &str) -> Option<(String, String)> {
fn sky_closed(input: &str) -> Option<(String, String)> {
match input.split_once('}') {
None => (return None),
None => return None,
Some((left, end)) => {
if left.ends_with('\\') {
match sky_closed(end) {
None => (return None),
None => return None,
Some((mid, right)) => {
let mut start: String = left.to_string();
start.push('}');

View file

@ -8,14 +8,11 @@ struct Message {
#[derive(Debug, Deserialize)]
struct InviteData {
// id: String,
// token: String,
// isUsed: bool,
#[serde(rename = "isHighTier")]
is_high_tier: bool,
// isCustom: bool,
}
/// Get information about an invite
#[poise::command(slash_command, ephemeral)]
pub async fn invites(
ctx: Context<'_>,

148
src/commands/links/all.rs Normal file
View file

@ -0,0 +1,148 @@
use crate::{commands::utils, Context, Error};
use cached::proc_macro::cached;
use chrono::{DateTime, Utc};
use log::info;
use super::{
cmore::{self, CmoreEvent},
eurosport::{self, ESEvents},
nfl::{self, NFLEvent},
viaplay::{self, ViaplayEvent},
Timeframe,
};
#[derive(Clone)]
enum Events {
EuroSport(ESEvents),
Viaplay(ViaplayEvent),
NFL(NFLEvent),
Cmore(CmoreEvent),
}
impl Events {
fn filter(&self, filter: &str) -> bool {
if filter.is_empty() {
return true;
};
match self {
Events::EuroSport(event) => event.filter(&filter),
Events::Viaplay(event) => event.filter(&filter),
Events::NFL(event) => event.filter(&filter),
Events::Cmore(event) => event.filter(&filter),
}
}
fn to_string(&self) -> String {
match self {
Events::EuroSport(event) => event.to_string(),
Events::Viaplay(event) => event.to_string(),
Events::NFL(event) => event.to_string(),
Events::Cmore(event) => event.to_string(),
}
}
fn get_key(&self) -> (DateTime<Utc>, String) {
match self {
Events::EuroSport(event) => event.get_key(),
Events::Viaplay(event) => event.get_key(),
Events::NFL(event) => event.get_key(),
Events::Cmore(event) => event.get_key(),
}
}
pub fn comp(&self, when: &Timeframe) -> bool {
match self {
Events::EuroSport(event) => event.comp(when),
Events::Viaplay(event) => event.comp(when),
Events::NFL(event) => event.comp(when),
Events::Cmore(event) => event.comp(when),
}
}
}
async fn get_euro() -> Vec<Events> {
let url = super::super::super::SETTINGS
.read()
.unwrap()
.get_table("eurosport")
.expect("Expecting an eurosport section in the config")
.get("url")
.expect("Config error, please set the eurosport[url] value")
.clone()
.into_string()
.expect("Config error, please make sure eurosport[url] is a string");
let events = eurosport::get_eurosport_events(url).await;
match events {
Some(events) => events
.iter()
.map(|e| Events::EuroSport(e.to_owned()))
.collect(),
_ => vec![],
}
}
async fn get_viaplay() -> Vec<Events> {
match viaplay::get_schedule().await {
Some(events) => events
.iter()
.map(|e| Events::Viaplay(e.to_owned()))
.collect(),
None => vec![],
}
}
async fn get_nfl() -> Vec<Events> {
match nfl::get_current_schedule().await {
Some(events) => events.iter().map(|e| Events::NFL(e.to_owned())).collect(),
None => vec![],
}
}
async fn get_cmore() -> Vec<Events> {
match cmore::get_schedule().await {
Some(events) => events.iter().map(|e| Events::Cmore(e.to_owned())).collect(),
None => vec![],
}
}
#[cached(time = 3600)]
async fn get_events() -> Vec<Events> {
let mut events: Vec<Events> = vec![];
events.extend(get_euro().await);
events.extend(get_viaplay().await);
events.extend(get_nfl().await);
events.extend(get_cmore().await);
events.sort_unstable_by_key(|event| (event.get_key()));
events
}
/// All events filtered (Eurosport, NFL, Viaplay)
#[poise::command(slash_command, ephemeral)]
pub async fn all(
ctx: Context<'_>,
#[description = "Filter sessions for when they are/were happening"] timeframe: Timeframe,
#[description = "Content to filter on"] filter: Option<String>,
) -> Result<(), Error> {
let events = get_events().await;
match events {
events if events.len() == 0 => {
ctx.say("No events found. Either it's not among the implemented providers or your search is too stringent").await?;
}
events => {
info!("Found {} events from all events", events.len());
let strings = events
.into_iter()
.filter(|e| e.comp(&timeframe))
.filter(|e| match &filter {
None => true,
Some(f) => e.filter(f.as_str()),
})
.map(|e| e.to_string())
.collect();
let pages = utils::paginator(strings, 1900, "\n".to_string());
utils::paginate_string(ctx, pages).await?;
}
}
Ok(())
}

184
src/commands/links/cmore.rs Normal file
View file

@ -0,0 +1,184 @@
use crate::{commands::utils, Context, Error};
use cached::proc_macro::cached;
use chrono::{DateTime, Utc};
use log::{info, warn};
use reqwest::header::AUTHORIZATION;
use serde::Deserialize;
use super::Timeframe;
#[derive(Deserialize, Clone)]
pub struct CmoreEvent {
#[serde(rename = "assetId")]
id: u32,
#[serde(rename = "asset")]
data: CmoreData,
}
#[derive(Deserialize, Clone)]
pub struct CmoreData {
#[serde(default)]
description: String,
title: String,
subtitle: String,
duration: i64,
#[serde(rename = "liveBroadcastTime")]
#[serde(with = "cmore_date")]
start: DateTime<Utc>,
}
impl CmoreEvent {
pub fn filter(&self, filter: &str) -> bool {
if filter.is_empty() {
return true;
};
if self.data.description.contains(filter) {
return true;
}
if self.data.title.contains(filter) {
return true;
}
if self.data.subtitle.contains(filter) {
return true;
}
false
}
pub fn comp(&self, when: &Timeframe) -> bool {
let now = Utc::now();
match when {
Timeframe::Everything => true,
Timeframe::Current => {
self.data.start <= now
&& self.data.start + chrono::Duration::seconds(self.data.duration) >= now
}
Timeframe::Future => {
self.data.start + chrono::Duration::seconds(self.data.duration) >= now
}
Timeframe::Past => {
self.data.start + chrono::Duration::seconds(self.data.duration) <= now
} // _ => self.data.times.end >= now,
}
}
pub fn to_string(&self) -> String {
format!(
"```md\n[{title}]({subtitle})```(<t:{start}:R>-<t:{end}:R>) https://tom.al/ms/cm/{id}",
title = self.data.title,
subtitle = self.data.subtitle,
start = self.data.start.timestamp(),
end = self.data.start.timestamp() + self.data.duration,
id = self.id
)
}
pub fn get_key(&self) -> (DateTime<Utc>, String) {
(self.data.start, self.data.description.clone())
}
}
mod cmore_date {
use chrono::{DateTime, TimeZone, Utc};
use serde::{self, Deserialize, Deserializer};
const FORMAT: &'static str = "%Y-%m-%dT%H:%M:%SZ";
pub fn deserialize<'de, D>(deserializer: D) -> Result<DateTime<Utc>, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
Utc.datetime_from_str(&s, FORMAT)
.map_err(serde::de::Error::custom)
}
}
#[cached(time = 3600)]
pub async fn get_schedule() -> Option<Vec<CmoreEvent>> {
let token = super::super::super::SETTINGS
.read()
.unwrap()
.get_table("morningstreams")
.unwrap()
.get("token")
.expect("Config error, please set the morningstreams[token] value")
.clone()
.into_string()
.expect("Config error, please make sure morningstreams[token] is a string");
let client = reqwest::Client::new();
let req = client
.get(format!(
"https://api.morningstreams.com/api/hightier/cmore/schedule"
))
.header(AUTHORIZATION, token)
.send()
.await;
let result: Option<Vec<CmoreEvent>> = match req {
Err(e) => {
warn!("Error getting Cmore schedule {}", e);
None
}
Ok(req) if req.status().as_u16() == 404 => {
warn!("404 on getting cmore events");
None
}
Ok(req) if req.status().as_u16() == 200 => {
let data = req.json::<Vec<CmoreEvent>>().await;
match data {
Ok(d) => {
Some(d) // .iter().map(|e| e.asset.clone()).collect())
}
Err(e) => {
warn!("Error getting Cmore schedule {}", e);
None
}
}
}
Ok(req) => {
warn!(
"Unhandled status when parsing Cmore request {}",
req.status()
);
None
}
};
result
}
/// Cmore events listing
#[poise::command(slash_command, ephemeral)]
pub async fn cmore(
ctx: Context<'_>,
#[description = "Filter sessions for when they are/were happening, defaults to future"]
timeframe: Option<super::Timeframe>,
#[description = "Content to filter on"] filter: Option<String>,
) -> Result<(), Error> {
let tf = match timeframe {
None => Timeframe::Future,
Some(tf) => tf,
};
let events: Option<Vec<CmoreEvent>> = get_schedule().await;
match events {
None => {
ctx.say("Unable to get the events, try again later (it's cached so wait a bit...)")
.await?;
}
Some(evs) => {
info!("Found {} events from cmore", evs.len());
let filtered: Vec<String> = evs
.into_iter()
.filter(|e| e.comp(&tf))
.filter(|e| match &filter {
None => true,
Some(f) => e.filter(f.as_str()),
})
.map(|e| e.to_string())
.collect();
let pages = utils::paginator(filtered, 1900, "\n".to_string());
utils::paginate_string(ctx, pages).await?;
}
};
Ok(())
}

View file

@ -108,7 +108,7 @@ struct Eurosport {
}
#[derive(Debug, Clone)]
struct ESEvents {
pub struct ESEvents {
id: String,
sport: Option<String>,
name: String,
@ -119,7 +119,7 @@ struct ESEvents {
}
impl ESEvents {
fn filter(&self, filter: &str) -> bool {
pub fn filter(&self, filter: &str) -> bool {
if self.name.to_lowercase().contains(filter) {
return true;
};
@ -137,20 +137,19 @@ impl ESEvents {
return false;
}
fn comp(&self, when: &Option<Timeframe>) -> bool {
pub fn comp(&self, when: &Timeframe) -> bool {
let now = Utc::now();
match when {
Some(Timeframe::Everything) => true,
Some(Timeframe::Current) => self.start <= now && self.end >= now,
Some(Timeframe::Future) => self.end >= now,
Some(Timeframe::Past) => self.end <= now,
_ => self.end >= now,
Timeframe::Everything => true,
Timeframe::Current => self.start <= now && self.end >= now,
Timeframe::Future => self.end >= now,
Timeframe::Past => self.end <= now,
// _ => self.end >= now,
}
}
fn to_string(&self) -> String {
pub fn to_string(&self) -> String {
match &self.sport {
// None => format!("```md\n({}) {}```\n", self.name, self.secondary),
None => format!(
"```md\n({}) {}```(<t:{}:R>-<t:{}:R>) {}\n https://tom.al/ms/euro/{}",
self.name,
@ -172,6 +171,10 @@ impl ESEvents {
),
}
}
pub fn get_key(&self) -> (DateTime<Utc>, String) {
(self.start, self.name.clone())
}
}
fn get_events(v: Eurosport) -> Result<Vec<ESEvents>, serde_json::Error> {
@ -233,7 +236,7 @@ fn get_events(v: Eurosport) -> Result<Vec<ESEvents>, serde_json::Error> {
#[cached(time = 3600)]
#[allow(dead_code)]
async fn get_eurosport_events(url: String) -> Option<Vec<ESEvents>> {
pub async fn get_eurosport_events(url: String) -> Option<Vec<ESEvents>> {
let cookie = super::super::super::SETTINGS
.read()
.unwrap()
@ -282,19 +285,30 @@ async fn get_eurosport_events(url: String) -> Option<Vec<ESEvents>> {
}
}
}
_ => None,
Ok(req) => {
warn!(
"Eurosport Unhandled request result {}",
req.status().as_u16()
);
None
}
};
return result;
}
// Eurosport player events
#[poise::command(slash_command)]
/// Eurosport player events
#[poise::command(slash_command, ephemeral)]
pub async fn eurosport(
ctx: Context<'_>,
#[description = "Filter sessions for when they are/were happening, defaults to future"]
timeframe: Option<Timeframe>,
#[description = "Content to filter on"] filter: Option<String>,
) -> Result<(), Error> {
let tf = match timeframe {
None => Timeframe::Future,
Some(tf) => tf,
};
let url = super::super::super::SETTINGS
.read()
.unwrap()
@ -314,7 +328,7 @@ pub async fn eurosport(
info!("Found {} events from eurosport", evs.len());
let strings = evs
.into_iter()
.filter(|e| e.comp(&timeframe))
.filter(|e| e.comp(&tf))
.filter(|e| match &filter {
None => true,
Some(f) => e.filter(f.as_str()),
@ -336,6 +350,10 @@ pub async fn proc_olympics(
timeframe: Option<Timeframe>,
filter: Option<String>,
) -> Result<(), Error> {
let tf = match timeframe {
None => Timeframe::Future,
Some(tf) => tf,
};
let url = super::super::super::SETTINGS
.read()
.unwrap()
@ -355,7 +373,7 @@ pub async fn proc_olympics(
info!("Found {} events from eurosport olympics ", evs.len());
let strings = evs
.into_iter()
.filter(|e| e.comp(&timeframe))
.filter(|e| e.comp(&tf))
.filter(|e| match &filter {
None => true,
Some(f) => e.filter(f.as_str()),

View file

@ -12,6 +12,7 @@ async fn autocomplete_season<'a>(
) -> impl Iterator<Item = String> + 'a {
(1981..2023)
.map(|n: u32| n.to_string())
.rev()
.filter(move |e| e.starts_with(&partial))
.map(|e| e.to_string())
}
@ -31,7 +32,6 @@ impl MSEvent {
fn get_title(&self) -> String {
let title = &self.metadata.attributes.series.replace("FORMULA", "F");
format!("**{}: {}**", title, self.metadata.brief)
// format!("", sport=self.content.format.sport, title=self.content.title, synopsis=self.content.synopsis, start=self.times.start.timestamp(), end=self.times.end.timestamp(), desc=self.content.description, id=self.system.product_key)
}
fn get_value(&self) -> String {
@ -194,8 +194,8 @@ async fn get_sessions(season: String) -> Option<Season> {
result
}
// F1TV links throughout the seasons
#[poise::command(slash_command)]
/// F1TV links throughout the seasons
#[poise::command(slash_command, ephemeral)]
pub async fn f1(
ctx: Context<'_>,
#[description = "Which season to pull from?"]
@ -237,7 +237,7 @@ pub async fn f1(
})
.await?;
while let Some(mci) = serenity::CollectComponentInteraction::new(ctx.discord())
while let Some(mci) = serenity::CollectComponentInteraction::new(ctx)
.channel_id(ctx.channel_id())
.filter(move |mci| mci.data.custom_id == content_id.to_string())
.await
@ -247,7 +247,7 @@ pub async fn f1(
let ses = get_event(session).await;
println!("Now responding to interaction");
match mci
.create_interaction_response(ctx.discord(), |ir| {
.create_interaction_response(ctx, |ir| {
ir.kind(serenity::InteractionResponseType::UpdateMessage)
.interaction_response_data(|m| match ses {
None => m.content("Unable to get these events :("),

View file

@ -1,7 +1,10 @@
use crate::{Context, Error};
mod all;
mod cmore;
mod eurosport;
mod f1;
mod nfl;
mod viaplay;
mod wrc;
@ -17,49 +20,19 @@ pub enum Timeframe {
Everything,
}
// #[derive(Debug, poise::ChoiceParameter)]
// pub enum Source {
// #[name = "Get links for the Eurosport player"]
// Eurosport,
// // #[name = "Get links for the apocalympics Eurosport player"]
// // Olympics,
// #[name = "Get WRC links for the WRC player"]
// WRC,
// #[name = "Get Viaplay links for the Viaplay player"]
// Viaplay,
// // #[name = "F1 content for the weekend"]
// // F1,
// }
/// Get links for high tier commands.
// #[poise::command(slash_command)]
// pub async fn links2(
// ctx: Context<'_>,
// #[description = "Where to git the juicy links from?"] source: Source,
// #[description = "Filter sessions for when they are/were happening, defaults to future"]
// timeframe: Option<Timeframe>,
// #[description = "Content to filter on"] filter: Option<String>,
// ) -> Result<(), Error> {
// if !utils::high_tier(ctx).await {
// ctx.say("This command can only be used in high tier channels for security")
// .await?;
// return Ok(());
// }
// match source {
// Source::Eurosport => eurosport::proc_eurosport(ctx, timeframe, filter).await,
// // Source::Olympics => eurosport::proc_olympics(ctx, timeframe, filter).await,
// Source::WRC => wrc::wrc(ctx).await,
// Source::Viaplay => viaplay::viaplay(ctx, timeframe, filter).await,
// // Source::F1 => f1::proc_f1(ctx, timeframe, filter).await,
// }
// // Ok(())
// }
#[poise::command(
slash_command,
subcommands("viaplay::viaplay", "eurosport::eurosport", "wrc::wrc", "f1::f1")
subcommands(
"viaplay::viaplay",
"viaplay::viaplay_schedule",
"eurosport::eurosport",
"wrc::wrc",
"f1::f1",
"nfl::nfl",
"cmore::cmore",
"all::all"
),
ephemeral
)]
pub async fn links(ctx: Context<'_>) -> Result<(), Error> {
ctx.say("Hello there!").await?;

240
src/commands/links/nfl.rs Normal file
View file

@ -0,0 +1,240 @@
use crate::{commands::utils, Context, Error};
use cached::proc_macro::cached;
use chrono::{DateTime, Duration, Utc};
use log::{info, warn};
use reqwest::header::AUTHORIZATION;
use serde::Deserialize;
use super::Timeframe;
mod str_to_u8 {
use serde::{self, Deserialize, Deserializer};
pub fn deserialize<'de, D>(deserializer: D) -> Result<u8, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
Ok(s.parse::<u8>().unwrap())
}
}
mod nfl_date {
use chrono::{DateTime, TimeZone, Utc};
use serde::{self, Deserialize, Deserializer};
const FORMAT: &'static str = "%Y-%m-%dT%H:%M:%S.%fZ";
pub fn deserialize<'de, D>(deserializer: D) -> Result<DateTime<Utc>, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
Utc.datetime_from_str(&s, FORMAT)
.map_err(serde::de::Error::custom)
}
}
#[derive(Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
struct NFLContext {
#[serde(with = "str_to_u8")]
current_week: u8,
}
#[derive(Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct NFLEvent {
home_nick_name: String,
visitor_nick_name: String,
#[serde(with = "nfl_date")]
game_date_time_utc: DateTime<Utc>,
video: NFLVideo,
}
#[derive(Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
struct NFLVideo {
title: String,
video_id: String,
}
impl NFLEvent {
pub fn filter(&self, filter: &str) -> bool {
if filter.is_empty() {
return true;
};
if self.video.title.contains(filter) {
return true;
}
false
}
pub fn comp(&self, when: &Timeframe) -> bool {
let now = Utc::now();
match when {
Timeframe::Everything => true,
Timeframe::Current => {
self.game_date_time_utc <= now
&& (self.game_date_time_utc + Duration::minutes(240)) >= now
}
Timeframe::Future => (self.game_date_time_utc + Duration::minutes(240)) >= now,
Timeframe::Past => self.game_date_time_utc <= now,
}
}
pub fn to_string(&self) -> String {
format!(
"```fix\n{home}-{away} ||{title}```<t:{time}:R> https://tom.al/ms/nfl/{id}",
title = self.video.title,
id = self.video.video_id,
time = self.game_date_time_utc.timestamp(),
home = self.home_nick_name,
away = self.visitor_nick_name,
)
}
pub fn get_key(&self) -> (DateTime<Utc>, String) {
(self.game_date_time_utc, self.video.title.to_owned())
}
}
#[cached(time = 3600)]
async fn get_week() -> Option<NFLContext> {
let token = super::super::super::SETTINGS
.read()
.unwrap()
.get_table("morningstreams")
.unwrap()
.get("token")
.expect("Config error, please set the morningstreams[token] value")
.clone()
.into_string()
.expect("Config error, please make sure morningstreams[token] is a string");
let client = reqwest::Client::new();
let req = client
.get("https://api.morningstreams.com/api/hightier/nfl/current-context")
.header(AUTHORIZATION, token)
.send()
.await;
match req {
Err(e) => {
warn!("Error getting NFL context {}", e);
None
}
Ok(req) => match req.json::<NFLContext>().await {
Ok(data) => Some(data),
Err(e) => {
warn!("Error parsing NFL context {}", e);
None
}
},
}
}
pub async fn get_current_schedule() -> Option<Vec<NFLEvent>> {
match get_week().await {
None => return None,
Some(w) => return get_schedule(w.current_week).await,
}
}
#[cached(time = 3600)]
async fn get_schedule(week: u8) -> Option<Vec<NFLEvent>> {
let token = super::super::super::SETTINGS
.read()
.unwrap()
.get_table("morningstreams")
.unwrap()
.get("token")
.expect("Config error, please set the morningstreams[token] value")
.clone()
.into_string()
.expect("Config error, please make sure morningstreams[token] is a string");
let client = reqwest::Client::new();
let req = client
.get(format!(
"https://api.morningstreams.com/api/hightier/nfl/schedule/{}",
week
))
.header(AUTHORIZATION, token)
.send()
.await;
let result: Option<Vec<NFLEvent>> = match req {
Err(e) => {
warn!("Error getting NFL schedule {}", e);
None
}
Ok(req) if req.status().as_u16() == 404 => {
warn!("404 on getting NFL events");
None
}
Ok(req) if req.status().as_u16() == 200 => {
let data = req.json::<Vec<NFLEvent>>().await;
match data {
Ok(d) => Some(d),
Err(e) => {
warn!("Error getting NFL schedule {}", e);
None
}
}
}
Ok(req) => {
warn!("Unhandled status when parsing NFL request {}", req.status());
None
}
};
result
}
/// NFL events listing
#[poise::command(slash_command, ephemeral)]
pub async fn nfl(
ctx: Context<'_>,
#[description = "Filter sessions for when they are/were happening, defaults to future"]
timeframe: Option<super::Timeframe>,
#[description = "Content to filter on"] filter: Option<String>,
#[description = "Which game week? (Defaults to current)"] week: Option<u8>,
) -> Result<(), Error> {
let tf = match timeframe {
None => Timeframe::Future,
Some(tf) => tf,
};
let get_week: u8 = match week {
Some(w) => w,
None => match get_week().await {
None => {
ctx.say("Error getting current week data, try setting one manually")
.await?;
return Ok(());
}
Some(w) => w.current_week,
},
};
let events: Option<Vec<NFLEvent>> = get_schedule(get_week).await;
match events {
None => {
ctx.say("Unable to get the events, try a different game week or try again later (it's cached so wait a bit...)")
.await?;
}
Some(evs) => {
info!("Found {} events from NFL", evs.len());
let filtered: Vec<String> = evs
.into_iter()
.filter(|e| e.comp(&tf))
.filter(|e| match &filter {
None => true,
Some(f) => e.filter(f.as_str()),
})
.map(|e| e.to_string())
.collect();
let pages = utils::paginator(filtered, 1900, "\n".to_string());
utils::paginate_string(ctx, pages).await?;
}
};
Ok(())
}

View file

@ -2,7 +2,7 @@ use std::{collections::HashSet, fmt};
use crate::{commands::utils, Context, Error};
use cached::proc_macro::cached;
use chrono::{DateTime, Utc};
use chrono::{DateTime, Duration, NaiveDate, Utc};
use futures::{Stream, StreamExt};
use log::{info, warn};
use reqwest::header::AUTHORIZATION;
@ -10,21 +10,8 @@ use serde::Deserialize;
use super::Timeframe;
// const translations: HashMap<String, String> = HashMap::from([
// ("Valioliiga", "Premier league"),
// ("Gjensidige Kvindeliga", "Mutual Women's League (Norway)"),
// ("Tanskan 1. divisioona", "Danish 1st Division"),
// ("Bundesliiga", "Bundesliga"),
// ("2. Bundesliiga", "2. Bundesliga"),
// ]);
// #[derive(Deserialize, Clone)]
// struct ViaplaySchedule {
// events: Vec<ViaplayEvent>,
// }
#[derive(Deserialize, Clone)]
struct ViaplayEvent {
pub struct ViaplayEvent {
content: Content,
#[serde(rename = "epg")]
times: EPG,
@ -32,28 +19,37 @@ struct ViaplayEvent {
}
impl ViaplayEvent {
fn filter(&self, filter: &str) -> bool {
pub fn filter(&self, filter: &str) -> bool {
if filter.is_empty() {
return true;
};
if self.content.format.sport.contains(filter) {
return true;
}
if self.content.description.contains(filter) {
return true;
}
if self.content.title.contains(filter) {
return true;
}
if self.content.synopsis.contains(filter) {
return true;
}
false
}
fn comp(&self, when: &Option<Timeframe>) -> bool {
pub fn comp(&self, when: &Timeframe) -> bool {
let now = Utc::now();
match when {
Some(Timeframe::Everything) => true,
Some(Timeframe::Current) => self.times.start <= now && self.times.end >= now,
Some(Timeframe::Future) => self.times.end >= now,
Some(Timeframe::Past) => self.times.end <= now,
_ => self.times.end >= now,
Timeframe::Everything => true,
Timeframe::Current => self.times.start <= now && self.times.end >= now,
Timeframe::Future => self.times.end >= now,
Timeframe::Past => self.times.end <= now,
// _ => self.times.end >= now,
}
}
fn to_string(&self) -> String {
pub fn to_string(&self) -> String {
format!("```md\n[{sport}]({title}) {synopsis}```(<t:{start}:R>-<t:{end}:R>) {desc}\nhttps://tom.al/ms/vp/{id}", sport=self.content.format.sport, title=self.content.title, synopsis=self.content.synopsis, start=self.times.start.timestamp(), end=self.times.end.timestamp(), desc=self.content.description, id=self.system.product_key)
}
@ -63,18 +59,20 @@ impl ViaplayEvent {
Some(s) => self.content.format.sport.contains(s),
}
}
pub fn get_key(&self) -> (DateTime<Utc>, String) {
(self.times.start, self.content.title.clone())
}
}
impl fmt::Display for ViaplayEvent {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Use `self.number` to refer to each positional data point.
// write!(f, "```md\n[{sport}]({title}) {synopsis}```(<t:{start}:R>-<t:{end}:R>) {desc}\nhttps://tom.al/ms/vp/{id}", sport=self.content.format.sport, title=self.content.title, synopsis=self.content.synopsis, start=self.times.start.timestamp(), end=self.times.end.timestamp(), desc=self.content.description, id=self.system.product_key)
write!(f, "{}", self.to_string())
}
}
#[derive(Deserialize, Clone)]
struct Content {
pub struct Content {
format: Format,
title: String,
#[serde(rename = "originalTitle")]
@ -96,7 +94,7 @@ struct Format {
sport: String,
}
#[derive(Deserialize, Clone)]
struct EPG {
pub struct EPG {
#[serde(with = "viaplay_date")]
start: DateTime<Utc>,
#[serde(with = "viaplay_date")]
@ -139,13 +137,16 @@ mod viaplay_sport {
"Bundesliiga" => Ok("Bundesliga".to_string()),
"2. Bundesliiga" => Ok("2. Bundesliga".to_string()),
"Hevosurheilu" => Ok("Equestrian sport".to_string()),
"Skotlannin Valioliiga" => Ok("Scottish Premier League".to_string()),
"Käsipallon Bundesliiga" => Ok("Handball Bundesliga".to_string()),
"Tanskan Bundesliiga" => Ok("Danish Superliga".to_string()),
_ => Ok(s.to_string()),
}
}
}
#[cached(time = 3600)]
async fn get_schedule() -> Option<Vec<ViaplayEvent>> {
#[cached(time = 7200)]
pub async fn get_schedule() -> Option<Vec<ViaplayEvent>> {
let token = super::super::super::SETTINGS
.read()
.unwrap()
@ -195,7 +196,60 @@ async fn get_schedule() -> Option<Vec<ViaplayEvent>> {
result
}
#[cached(time = 3600)]
#[cached(time = 36000)]
pub async fn get_schedule_date(date: NaiveDate) -> Option<Vec<ViaplayEvent>> {
let client = reqwest::Client::new();
let req = client
.get(format!(
"https://content.viaplay.fi/pcdash-fi/urheilu?date={}",
date.format("%Y-%m-%d")
))
.send()
.await;
let result: Option<Vec<ViaplayEvent>> = match req {
Err(e) => {
warn!("Error getting Viaplay schedule {}", e);
None
}
Ok(req) if req.status().as_u16() == 404 => {
warn!("404 on getting VP events");
None
}
Ok(req) if req.status().as_u16() == 200 => {
let data = req.json::<serde_json::Value>().await;
Some(
serde_json::from_value::<Vec<ViaplayEvent>>(
data.unwrap_or(serde_json::Value::Null)
.get("_embedded")
.unwrap_or(&serde_json::Value::Null)
.get("viaplay:blocks")
.unwrap_or(&serde_json::Value::Null)
.as_array()
.unwrap_or(&vec![])
.last()
.unwrap_or(&serde_json::Value::Null)
.get("_embedded")
.unwrap_or(&serde_json::Value::Null)
.get("viaplay:products")
.unwrap_or(&serde_json::Value::Null)
.clone(),
)
.unwrap_or(vec![]),
)
}
Ok(req) => {
warn!(
"Unhandled status when parsing viaplay request {}",
req.status()
);
None
}
};
result
}
#[cached(time = 7200)]
pub async fn get_sports() -> Vec<String> {
// let events = get_schedule();
if let Some(events) = get_schedule().await {
@ -209,15 +263,6 @@ pub async fn get_sports() -> Vec<String> {
}
}
// #[allow(dead_code)]
// async fn autocomplete_sport(_ctx: Context<'_>, partial: String) -> impl Stream<Item = String> {
// // futures::stream::iter(get_sports().iter())
// // .filter(move |name| futures::future::ready(name.contains(&partial)))
// // .map(|name| name.to_string())
// futures::stream::iter(get_sports().await)
// .filter(move |name| futures::future::ready(name.contains(&partial)))
// }
async fn autocomplete_sport<'a>(
_ctx: Context<'_>,
partial: &'a str,
@ -227,8 +272,8 @@ async fn autocomplete_sport<'a>(
.map(|name| name.to_string())
}
//Viaplay events listing
#[poise::command(slash_command)]
/// Viaplay schedule for the day
#[poise::command(slash_command, ephemeral)]
pub async fn viaplay(
ctx: Context<'_>,
#[description = "Filter sessions for when they are/were happening, defaults to future"]
@ -238,6 +283,10 @@ pub async fn viaplay(
#[autocomplete = "autocomplete_sport"]
sport: Option<String>,
) -> Result<(), Error> {
let tf = match timeframe {
None => Timeframe::Future,
Some(tf) => tf,
};
let events: Option<Vec<ViaplayEvent>> = get_schedule().await;
match events {
None => {
@ -248,7 +297,7 @@ pub async fn viaplay(
info!("Found {} events from viaplay", evs.len());
let filtered: Vec<String> = evs
.into_iter()
.filter(|e| e.comp(&timeframe))
.filter(|e| e.comp(&tf))
.filter(|e| e.check_sport(&sport))
.filter(|e| match &filter {
None => true,
@ -263,19 +312,40 @@ pub async fn viaplay(
Ok(())
}
// /// Another subcommand of `parent`
// #[poise::command(slash_command)]
// pub async fn child3(
// ctx: Context<'_>,
// #[description = "Where to git the juicy links from?"]
// _source: super::Source,
// #[description = "Filter sessions for when they are/were happening, defaults to future"]
// _timeframe: Option<super::Timeframe>,
// #[description = "Content to filter on"] filter: Option<String>,
// #[description = "Filter for which sport to list (only Viaplay)"]
// #[autocomplete = "autocomplete_sport"]
// sport: Option<String>,
// ) -> Result<(), Error> {
// ctx.say("You invoked the second child command!").await?;
// Ok(())
// }
/// Viaplay schedule for specified date
#[poise::command(slash_command, ephemeral)]
pub async fn viaplay_schedule(
ctx: Context<'_>,
#[description = "Offset for amount fo days from today (0 for current day)"] offset: Option<i8>,
#[description = "Content to filter on"] filter: Option<String>,
) -> Result<(), Error> {
let offset: i8 = offset.unwrap_or_default();
let date = Utc::now()
.date_naive()
.checked_add_signed(Duration::days(offset.into()))
.expect("Expected an existing date as result");
let schedule = get_schedule_date(date).await;
let title = format!("`Viaplay schedule for {}`", date.format("%d-%m-%Y"));
match schedule {
None => {
ctx.say("Unable to get the events, try again later (it's cached so wait a bit...)")
.await?;
}
Some(evs) => {
info!("Found {} events from viaplay", evs.len());
let filtered: Vec<String> = evs
.into_iter()
.filter(|e| match &filter {
None => true,
Some(f) => e.filter(f.as_str()),
})
.map(|e| e.to_string())
.collect();
let pages = utils::paginator_title(title, filtered, 1900, "\n".to_string());
utils::paginate_string(ctx, pages).await?;
}
};
Ok(())
}

View file

@ -22,10 +22,6 @@ mod wrc_date {
#[derive(Deserialize)]
struct WRC {
// #[serde(rename = "earliestPlayableStart")]
// #[serde(with = "es_date_time")]
// earliest_playable_start: DateTime<Utc>,
// id: u32,
name: String,
#[serde(rename = "eventDays")]
days: Vec<WRCDays>,
@ -33,7 +29,6 @@ struct WRC {
#[derive(Deserialize)]
struct WRCDays {
// id: u32,
#[serde(rename = "eventDay")]
event_day: String,
#[serde(rename = "spottChannel")]
@ -42,20 +37,15 @@ struct WRCDays {
#[derive(Deserialize)]
struct WRCChannel {
// id: u32,
// #[serde(rename = "displayName")]
// name: String,
assets: Vec<WRCAssets>,
}
#[derive(Deserialize)]
struct WRCAssets {
// id: u32,
#[serde(with = "wrc_date")]
start: DateTime<Utc>,
#[serde(with = "wrc_date")]
end: DateTime<Utc>,
// duration: u32,
content: WRCContent,
}
@ -84,13 +74,10 @@ async fn get_schedule() -> Result<Option<WRC>, Error> {
}
}
// WRC sessions
#[poise::command(slash_command)]
/// WRC sessions
#[poise::command(slash_command, ephemeral)]
pub async fn wrc(
ctx: Context<'_>,
// #[description = "Filter sessions for when they are/were happening, defaults to future"]
// timeframe: Option<super::Timeframe>,
// #[description = "Content to filter on"] filter: Option<String>,
) -> Result<(), Error> {
let wrc = get_schedule().await?;
match wrc {
@ -107,7 +94,7 @@ pub async fn wrc(
} else {
"".to_string()
};
events.push(format!("{}: <t:{}:R>- <t:{}:R>: [{}](https://morningstreams.com/wrcplayer.html?id={}) {} {}", day.event_day, session.start.timestamp(), session.end.timestamp(), session.content.id, session.content.id, session.content.title, desc));
events.push(format!("{}: <t:{}:R>- <t:{}:R>: [{}](https://tom.al/ms/wrc/{}) {} {}", day.event_day, session.start.timestamp(), session.end.timestamp(), session.content.id, session.content.id, session.content.title, desc));
}
}
let pages = utils::paginator(events, 2400, "\n".to_owned());

View file

@ -3,8 +3,8 @@ use poise::serenity_prelude as serenity;
pub mod invites;
mod links;
// pub mod planning;
pub mod coms;
pub mod roles;
pub mod schedule;
pub mod utils;
@ -27,16 +27,15 @@ pub async fn boop(ctx: Context<'_>) -> Result<(), Error> {
.await?;
let mut boop_count: i32 = 0;
while let Some(mci) = serenity::CollectComponentInteraction::new(ctx.discord())
while let Some(mci) = serenity::CollectComponentInteraction::new(ctx)
.channel_id(ctx.channel_id())
// .timeout(std::time::Duration::from_secs(1200))
.filter(move |mci| mci.data.custom_id == uuid_boop.to_string())
.await
{
boop_count += 1;
let mut msg = mci.message.clone();
msg.edit(ctx.discord(), |m| {
msg.edit(ctx, |m| {
m.content(match boop_count {
2 => "Boop count: <:HamSmile:738765923401596991>".to_string(),
3 => "Boop 3".to_string(),
@ -60,7 +59,7 @@ pub async fn boop(ctx: Context<'_>) -> Result<(), Error> {
})
.await?;
mci.create_interaction_response(ctx.discord(), |ir| {
mci.create_interaction_response(ctx, |ir| {
ir.kind(serenity::InteractionResponseType::DeferredUpdateMessage)
})
.await?;
@ -69,6 +68,7 @@ pub async fn boop(ctx: Context<'_>) -> Result<(), Error> {
Ok(())
}
/// Imaginary fix button
#[poise::command(track_edits, slash_command)]
pub async fn fix(ctx: Context<'_>) -> Result<(), Error> {
let uuid_fix = ctx.id();
@ -88,21 +88,20 @@ pub async fn fix(ctx: Context<'_>) -> Result<(), Error> {
.await?;
let mut fix_count: i32 = 0;
while let Some(mci) = serenity::CollectComponentInteraction::new(ctx.discord())
while let Some(mci) = serenity::CollectComponentInteraction::new(ctx)
.channel_id(ctx.channel_id())
// .timeout(std::time::Duration::from_secs(1200))
.filter(move |mci| mci.data.custom_id == uuid_fix.to_string())
.await
{
fix_count += 1;
let mut msg = mci.message.clone();
msg.edit(ctx.discord(), |m| {
msg.edit(ctx, |m| {
m.content(format!("Fixing failed try again. Attempt {}", fix_count))
})
.await?;
mci.create_interaction_response(ctx.discord(), |ir| {
mci.create_interaction_response(ctx, |ir| {
ir.kind(serenity::InteractionResponseType::DeferredUpdateMessage)
})
.await?;
@ -114,14 +113,5 @@ pub async fn fix(ctx: Context<'_>) -> Result<(), Error> {
pub fn get_links(
) -> poise::Command<super::Data, Box<(dyn std::error::Error + std::marker::Send + Sync + 'static)>>
{
// poise::Command {
// subcommands: vec![
// links::eurosport::eurosport(),
// links::eurosport::olympics(),
// links::links(),
// // Let's make sure poise isn't confused by the duplicate names!
// ],
// ..links::links()
// };
links::links()
}

View file

@ -63,7 +63,7 @@ pub async fn series(
Ok(())
}
#[derive(Debug, poise::SlashChoiceParameter)]
#[derive(Debug, poise::ChoiceParameter)]
pub enum Timeframe {
#[name = "Currently happening"]
Current,

91
src/commands/roles.rs Normal file
View file

@ -0,0 +1,91 @@
use crate::{Context, Error};
use poise::serenity_prelude::RoleId;
#[derive(Debug, poise::ChoiceParameter)]
pub enum Action {
#[name = "Add specified role."]
Add,
#[name = "Remove specified role."]
Remove,
#[name = "Toggle specified role (default)."]
Toggle,
}
async fn autocomplete_role<'a>(
ctx: Context<'_>,
partial: &'a str,
) -> impl Iterator<Item = String> + 'a {
let mut roles: Vec<String> = match super::super::SETTINGS
.read()
.unwrap()
.get_table("roles")
.unwrap()
.get(&ctx.guild_id().expect("Not in a guild").to_string())
{
None => {
vec![]
}
Some(val) => match val.clone().into_table() {
Err(_) => {
vec![]
}
Ok(val) => val
.into_keys()
.filter(|str| str.contains(partial))
.collect(),
},
};
roles.sort_unstable();
roles.into_iter() //.map(|a| a.to_owned())
}
#[poise::command(slash_command, ephemeral, guild_only)]
pub async fn roles(
ctx: Context<'_>,
#[description = "Which role to add or remove?"]
#[autocomplete = "autocomplete_role"]
role: String,
#[description = "Remove or add role (default to add)"] action: Option<Action>,
) -> Result<(), Error> {
let role = super::super::SETTINGS
.read()
.unwrap()
.get_table("roles")
.unwrap()
.get(&ctx.guild_id().unwrap().to_string())
.expect("Command is only supported in a server")
.clone()
.into_table()
.expect("Config error, something in the configuration is wrong. Please contact someone to fix the bot.")
.get(&role)
.expect("Configured role does not exist")
.clone()
.into_uint()
.expect("Config error, specified role does not have the role_id configured.");
let role_ding = RoleId(role);
let mut member = ctx.author_member().await.expect("Where's my member....");
let mem = member.to_mut();
// if let Some(mut author) = ctx.author_member().await.as_mut().expect("Somehow there's no member object attached...") {
match action {
Some(Action::Remove) => {
mem.remove_role(ctx, role_ding).await?;
ctx.say(format!("Role {} Added", role)).await?
}
Some(Action::Add) => {
mem.add_role(ctx, role_ding).await?;
ctx.say(format!("Role {} Added", role)).await?
}
_ => {
if mem.roles.contains(&role_ding) {
mem.remove_role(ctx, role_ding).await?;
ctx.say(format!("Role {} Added", role)).await?
} else {
mem.add_role(ctx, role_ding).await?;
ctx.say(format!("Role {} Added", role)).await?
}
}
};
Ok(())
}

View file

@ -31,14 +31,14 @@ impl MSEvent {
fn get_value(&self, high_tier: bool) -> String {
let link = if high_tier {
format!(
"[{id}](https://morningstreams.com/hightier/f1/session/{id})\n",
"[{id}](https://morningstreams.com/hightier/f1/session/{id})",
id = self.id
)
} else {
"".to_string()
};
format!(
"{link}Start: <t:{start}:R>\nEnd: <t:{end}:R>",
"{link}\nStart: <t:{start}:R>\nEnd: <t:{end}:R>",
link = link,
start = self.metadata.attributes.start.timestamp(),
end = self.metadata.attributes.end.timestamp()
@ -136,7 +136,8 @@ async fn get_schedule() -> Option<MSReq> {
result
}
#[poise::command(slash_command)]
// Get the most recent F1 schedule
#[poise::command(slash_command, ephemeral)]
pub async fn schedule(ctx: Context<'_>) -> Result<(), Error> {
let events: Option<MSReq> = get_schedule().await;
let ht: bool = utils::high_tier(ctx).await;

View file

@ -11,13 +11,13 @@ pub async fn high_tier(ctx: Context<'_>) -> bool {
_ => (),
}
match ctx.discord().cache.guild_channel(ctx.channel_id()) {
match ctx.serenity_context().cache.guild_channel(ctx.channel_id()) {
None => return false,
Some(chan) => match chan.parent_id {
None => return false,
Some(cat_id) => match cat_id {
ChannelId(547551264498515978) => return true,
ChannelId(884698356360818708) => return true,
ChannelId(547551264498515978) => return true, // MS high tier
ChannelId(884698356360818708) => return true, // Private server
_ => return false,
},
},
@ -44,6 +44,32 @@ pub fn paginator(input: Vec<String>, chunk_size: usize, join_string: String) ->
return result;
}
pub fn paginator_title(
title: String,
input: Vec<String>,
chunk_size: usize,
join_string: String,
) -> Vec<String> {
if input.len() == 0 {
return vec![];
}
let mut result: Vec<String> = vec![];
let mut part: String = title.clone();
let filler = &join_string.chars().count();
for i in input {
if part.chars().count() + i.chars().count() + filler >= chunk_size {
result.push(part);
part = title.to_string();
part.push_str(&i.to_string());
} else {
part.push_str(&join_string);
part.push_str(&i.to_string());
}
}
result.push(part);
return result;
}
pub async fn paginate_string(ctx: Context<'_>, pages: Vec<String>) -> Result<(), Error> {
let uuid_command = ctx.id().to_string();
let page_count = pages.len();
@ -60,43 +86,40 @@ pub async fn paginate_string(ctx: Context<'_>, pages: Vec<String>) -> Result<(),
_ => {}
};
ctx.send(|m| {
m.content(format!(
"{}\n\nPage: {}/{}",
pages.get(0).unwrap(),
1,
page_count
))
.components(|c| {
c.create_action_row(|ar| {
ar.create_button(|b| {
b.style(serenity::ButtonStyle::Primary)
.label("Previous page")
.custom_id(format!("{}_previous", uuid_command))
});
ar.create_button(|b| {
b.style(serenity::ButtonStyle::Primary)
.label("Next page")
.custom_id(format!("{}_next", uuid_command))
});
ar.create_button(|b| {
b.style(serenity::ButtonStyle::Secondary)
.label("Reset")
.custom_id(format!("{}_close", uuid_command))
let reply_handle = ctx
.send(|m| {
m.content(format!(
"{}\n\nPage: {}/{}",
pages.get(0).unwrap(),
1,
page_count
))
.components(|c| {
c.create_action_row(|ar| {
ar.create_button(|b| {
b.style(serenity::ButtonStyle::Primary)
.label("Previous page")
.custom_id(format!("{}_previous", uuid_command))
});
ar.create_button(|b| {
b.style(serenity::ButtonStyle::Primary)
.label("Next page")
.custom_id(format!("{}_next", uuid_command))
});
ar.create_button(|b| {
b.style(serenity::ButtonStyle::Secondary)
.label("Reset")
.custom_id(format!("{}_close", uuid_command))
})
})
})
})
})
.await?;
// let interaction1 = if let ReplyHandle::Application { http, interaction } = msg.unwrap(){Some(interaction)} else {None};
// let interaction = interaction1.unwrap();
.await?;
let mut page = 0;
while let Some(mci) = serenity::CollectComponentInteraction::new(ctx.discord())
// .author_id(ctx.author().id)
while let Some(mci) = serenity::CollectComponentInteraction::new(ctx)
.channel_id(ctx.channel_id())
.timeout(std::time::Duration::from_secs(1200))
// .filter(move |mci| mci.data.custom_id == uuid_command.to_string())
.await
{
if !mci.data.custom_id.contains(&uuid_command) {
@ -115,18 +138,18 @@ pub async fn paginate_string(ctx: Context<'_>, pages: Vec<String>) -> Result<(),
page = 0;
}
let mut msg = mci.message.clone();
msg.edit(ctx.discord(), |m| {
m.content(format!(
"{}\n\nPage: {}/{}",
pages.get(page).unwrap(),
page + 1,
page_count
))
})
.await?;
reply_handle
.edit(ctx, |m| {
m.content(format!(
"{}\n\nPage: {}/{}",
pages.get(page).unwrap(),
page + 1,
page_count
))
})
.await?;
mci.create_interaction_response(ctx.discord(), |ir| {
mci.create_interaction_response(ctx, |ir| {
ir.kind(serenity::InteractionResponseType::DeferredUpdateMessage)
})
.await?;
@ -149,7 +172,6 @@ pub async fn paginate_string_embed(
return Ok(());
}
1 => {
// ctx.say(pages.get(0).unwrap()).await?;
ctx.send(|m| m.embed(|e| e.title(title).description(pages.get(0).unwrap())))
.await?;
return Ok(());
@ -157,47 +179,38 @@ pub async fn paginate_string_embed(
_ => {}
};
ctx.send(|m| {
// m.content(format!(
// "{}\n\nPage: {}/{}",
// pages.get(0).unwrap(),
// 1,
// page_count
// ))
m.embed(|e| {
e.title(format!("{} Page 1/{}", title, page_count))
.description(pages.get(0).unwrap())
})
.components(|c| {
c.create_action_row(|ar| {
ar.create_button(|b| {
b.style(serenity::ButtonStyle::Primary)
.label("Previous page")
.custom_id(format!("{}_previous", uuid_command))
});
ar.create_button(|b| {
b.style(serenity::ButtonStyle::Primary)
.label("Next page")
.custom_id(format!("{}_next", uuid_command))
});
ar.create_button(|b| {
b.style(serenity::ButtonStyle::Secondary)
.label("Reset")
.custom_id(format!("{}_close", uuid_command))
let reply_handle = ctx
.send(|m| {
m.embed(|e| {
e.title(format!("{} Page 1/{}", title, page_count))
.description(pages.get(0).unwrap())
})
.components(|c| {
c.create_action_row(|ar| {
ar.create_button(|b| {
b.style(serenity::ButtonStyle::Primary)
.label("Previous page")
.custom_id(format!("{}_previous", uuid_command))
});
ar.create_button(|b| {
b.style(serenity::ButtonStyle::Primary)
.label("Next page")
.custom_id(format!("{}_next", uuid_command))
});
ar.create_button(|b| {
b.style(serenity::ButtonStyle::Secondary)
.label("Reset")
.custom_id(format!("{}_close", uuid_command))
})
})
})
})
})
.await?;
// let interaction1 = if let ReplyHandle::Application { http, interaction } = msg.unwrap(){Some(interaction)} else {None};
// let interaction = interaction1.unwrap();
.await?;
let mut page = 0;
while let Some(mci) = serenity::CollectComponentInteraction::new(ctx.discord())
// .author_id(ctx.author().id)
while let Some(mci) = serenity::CollectComponentInteraction::new(ctx)
.channel_id(ctx.channel_id())
.timeout(std::time::Duration::from_secs(1200))
// .filter(move |mci| mci.data.custom_id == uuid_command.to_string())
.await
{
if !mci.data.custom_id.contains(&uuid_command) {
@ -216,16 +229,16 @@ pub async fn paginate_string_embed(
page = 0;
}
let mut msg = mci.message.clone();
msg.edit(ctx.discord(), |m| {
m.embed(|e| {
e.title(format!("{} Page {}/{}", title, page + 1, page_count))
.description(pages.get(page).unwrap())
reply_handle
.edit(ctx, |m| {
m.embed(|e| {
e.title(format!("{} Page {}/{}", title, page + 1, page_count))
.description(pages.get(page).unwrap())
})
})
})
.await?;
.await?;
mci.create_interaction_response(ctx.discord(), |ir| {
mci.create_interaction_response(ctx, |ir| {
ir.kind(serenity::InteractionResponseType::DeferredUpdateMessage)
})
.await?;

View file

@ -74,7 +74,7 @@ async fn register(
"Purging global commands, must have been a mistake eh?"
))
.await?;
ctx.discord()
ctx.serenity_context()
.http
.create_global_application_commands(&serenity::json::Value::Null)
.await?;
@ -85,7 +85,7 @@ async fn register(
commands.len()
))
.await?;
ctx.discord()
ctx.serenity_context()
.http
.create_global_application_commands(&commands_builder)
.await?;
@ -111,7 +111,7 @@ async fn register(
commands.len()
))
.await?;
ctx.discord()
ctx.serenity_context()
.http
.create_guild_application_commands(guild.id.0, &commands_builder)
.await?;
@ -122,12 +122,93 @@ async fn register(
Ok(())
}
/// Use the default configuration for setting up commands.
#[poise::command(
prefix_command,
hide_in_help,
// required_permissions = "MANAGE_MESSAGES | ADMINISTRATOR",
owners_only=true,
)]
async fn default_register(ctx: Context<'_>) -> Result<(), Error> {
// poise::builtins::register_application_commands(ctx, global).await?;
let is_bot_owner = ctx.framework().options().owners.contains(&ctx.author().id);
let mut commands_builder_guild = serenity::CreateApplicationCommands::default();
let commands = &ctx.framework().options().commands;
ctx.say(format!("Commands: {}", commands.len())).await?;
fn globals_filter(name: &String) -> bool {
name.starts_with("invite") || name.starts_with("boop") || name.starts_with("fix")
}
// If the user is the bot owner, also correct the global commands.
if is_bot_owner {
let mut commands_builder_global = serenity::CreateApplicationCommands::default();
// let global_commands = commands; //.iter().filter(|com| com.name.starts_with("invite")).collect();
let mut global_count = 0;
for command in commands {
if globals_filter(&command.name) {
global_count += 1;
if let Some(slash_command) = command.create_as_slash_command() {
commands_builder_global.add_application_command(slash_command);
}
if let Some(context_menu_command) = command.create_as_context_menu_command() {
commands_builder_global.add_application_command(context_menu_command);
}
}
}
let commands_build_global = serenity::json::Value::Array(commands_builder_global.0);
ctx.serenity_context()
.http
.create_global_application_commands(&commands_build_global)
.await?;
ctx.say(format!("Registered {} as global commands", global_count))
.await?;
}
let mut command_count: u8 = 0;
for command in commands {
if !globals_filter(&command.name) {
command_count += 1;
if let Some(slash_command) = command.create_as_slash_command() {
commands_builder_guild.add_application_command(slash_command);
}
if let Some(context_menu_command) = command.create_as_context_menu_command() {
commands_builder_guild.add_application_command(context_menu_command);
}
}
}
let commands_builder = serenity::json::Value::Array(commands_builder_guild.0);
let guild = match ctx.guild() {
Some(x) => x,
None => {
return Ok(());
}
};
let is_guild_owner = ctx.author().id == guild.owner_id;
if !is_guild_owner && !is_bot_owner {
ctx.say("Can only be used by server owner").await?;
return Ok(());
}
ctx.say(format!(
"Registering {} commands out of {}...",
command_count,
commands.len()
))
.await?;
ctx.serenity_context()
.http
.create_guild_application_commands(guild.id.0, &commands_builder)
.await?;
ctx.say("Done!").await?;
Ok(())
}
async fn on_error(error: poise::FrameworkError<'_, Data, Error>) {
// This is our custom error handler
// They are many errors that can occur, so we only handle the ones we want to customize
// and forward the rest to the default handler
match error {
poise::FrameworkError::Setup { error } => panic!("Failed to start bot: {:?}", error),
poise::FrameworkError::Setup { error, .. } => panic!("Failed to start bot: {:?}", error),
poise::FrameworkError::Command { error, ctx } => {
println!("Error in command `{}`: {:?}", ctx.command().name, error,);
}
@ -180,8 +261,10 @@ async fn app() -> Result<(), Error> {
let commands = vec![
help(),
register(),
default_register(),
commands::invites::invites(),
commands::schedule::schedule(),
commands::roles::roles(),
commands::boop(),
commands::fix(),
// commands::planning::get_command(),
@ -245,7 +328,7 @@ async fn app() -> Result<(), Error> {
let framework = poise::Framework::builder()
.token(token)
.user_data_setup(move |_ctx, _ready, _framework| {
.setup(move |_ctx, _ready, _framework| {
// Box::pin(async move { Ok(Data { database: database }) })
Box::pin(async move { Ok(Data { database: db }) })
})