Better time in events message + README.md and LICENSE.md
This commit is contained in:
parent
d8fe8edf04
commit
0e43b286ef
7 changed files with 196 additions and 36 deletions
31
Cargo.lock
generated
31
Cargo.lock
generated
|
@ -171,7 +171,7 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_bytes",
|
"serde_bytes",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"time",
|
"time 0.3.22",
|
||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -213,8 +213,11 @@ checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"android-tzdata",
|
"android-tzdata",
|
||||||
"iana-time-zone",
|
"iana-time-zone",
|
||||||
|
"js-sys",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"serde",
|
"serde",
|
||||||
|
"time 0.1.45",
|
||||||
|
"wasm-bindgen",
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -612,7 +615,7 @@ checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"wasi",
|
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1075,7 +1078,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
|
checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"wasi",
|
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1180,8 +1183,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "obsessed-yanqing"
|
name = "obsessed-yanqing"
|
||||||
version = "1.2.0"
|
version = "1.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
"levenshtein",
|
"levenshtein",
|
||||||
"mongodb",
|
"mongodb",
|
||||||
"poise",
|
"poise",
|
||||||
|
@ -1863,7 +1867,7 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde-value",
|
"serde-value",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"time",
|
"time 0.3.22",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
"typemap_rev",
|
"typemap_rev",
|
||||||
|
@ -2075,6 +2079,17 @@ dependencies = [
|
||||||
"syn 2.0.27",
|
"syn 2.0.27",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time"
|
||||||
|
version = "0.1.45"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"wasi 0.10.0+wasi-snapshot-preview1",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time"
|
name = "time"
|
||||||
version = "0.3.22"
|
version = "0.3.22"
|
||||||
|
@ -2412,6 +2427,12 @@ dependencies = [
|
||||||
"try-lock",
|
"try-lock",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.10.0+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "obsessed-yanqing"
|
name = "obsessed-yanqing"
|
||||||
version = "1.3.0"
|
version = "1.3.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
authors = ["Evann Regnault"]
|
authors = ["Evann Regnault"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
@ -19,3 +19,4 @@ select = "0.6.0"
|
||||||
regex = "1.9.1"
|
regex = "1.9.1"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
mongodb = "2.6.0"
|
mongodb = "2.6.0"
|
||||||
|
chrono = "0.4.26"
|
||||||
|
|
21
LICENSE.md
Normal file
21
LICENSE.md
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2023 Evann REGNAULT
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
49
README.md
Normal file
49
README.md
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
# Obsessed Yanqing
|
||||||
|
|
||||||
|
This is a bot whose main purpose is to give as much infomrations as possible about Honkai Star Rail.
|
||||||
|
|
||||||
|
> ⚠️ Disclaimer : All Data is fetched from [Prydwen.gg](https://prydwen.gg)
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
### Event messages
|
||||||
|
The command `/create_event_message <channel>` creates, as its name indicate, an event message in the channel of your
|
||||||
|
choice.</br>This message will contain:
|
||||||
|
- All the currently running banners
|
||||||
|
- The currently going events
|
||||||
|
- The upcoming banners and events
|
||||||
|
- The currently known redeemable codes
|
||||||
|
|
||||||
|
> In order to update this message every hour, three information are stored in a database : Guild id, Channel id, Message id.
|
||||||
|
>
|
||||||
|
> ❗ Those are the only information stored by the bot !
|
||||||
|
|
||||||
|
|
||||||
|
### Character Data
|
||||||
|
|
||||||
|
By using the command `/character <character>`, you get access to loads of data about the selected character.
|
||||||
|
|
||||||
|
Such as its rarity, role, description, pros and cons, its different builds, and the recommended teams.
|
||||||
|
|
||||||
|
All the navigation is done by click and touch on the buttons bellow the message.
|
||||||
|
|
||||||
|
If a character has multiple builds/gears, you need to click on th gear button again to navigate to the next one.
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
If you want to setup this bot by yourself, a docker image is available on [my docker registry](https://registry.evannregnault.dev/#!/taglist/obsessed-yanqing).
|
||||||
|
|
||||||
|
You'll also need a mongoDB server alongside it.
|
||||||
|
|
||||||
|
### ENV
|
||||||
|
```env
|
||||||
|
TOKEN : The discord bot's token
|
||||||
|
MONGO_HOST : The hostname of the mongodb instance
|
||||||
|
MONGO_PORT : The port of the mongodb instance
|
||||||
|
```
|
||||||
|
|
||||||
|
## APIs / Libraries
|
||||||
|
|
||||||
|
- [Prydwen.gg](https://www.prydwen.gg/star-rail/)
|
||||||
|
- [Serenity](https://github.com/serenity-rs/serenity)
|
||||||
|
- [Poise](https://github.com/serenity-rs/poise)
|
|
@ -202,7 +202,7 @@ fn create_character_tabs_button<'a>(f: &'a mut CreateComponents, char: &Characte
|
||||||
gear_button.disabled(false);
|
gear_button.disabled(false);
|
||||||
match current_tab {
|
match current_tab {
|
||||||
CharacterTab::Gear(n) => {
|
CharacterTab::Gear(n) => {
|
||||||
gear_button.label(format!("Gear {}/{}", n+1, char.build_data.as_ref().expect("").len()));
|
gear_button.label(format!("Gear {}/{}", n+1, char.build_data.as_ref().expect("Cannot find gear").len()));
|
||||||
}
|
}
|
||||||
_ => {gear_button.label("Gear");}
|
_ => {gear_button.label("Gear");}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::i32;
|
use std::i32;
|
||||||
use std::str::Split;
|
use std::str::Split;
|
||||||
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
use chrono::{NaiveDateTime};
|
||||||
use regex::{Regex};
|
use regex::{Regex};
|
||||||
use select::document::Document;
|
use select::document::Document;
|
||||||
use select::node::Node;
|
use select::node::Node;
|
||||||
|
@ -32,11 +34,17 @@ struct BannerData {
|
||||||
four_stars: Vec<String>
|
four_stars: Vec<String>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct EventTime {
|
||||||
|
start: Option<i64>,
|
||||||
|
end: Option<i64>
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct Event {
|
struct Event {
|
||||||
name: String,
|
name: String,
|
||||||
description: Option<(String, String)>,
|
description: Option<(String, String)>,
|
||||||
time: Option<String>,
|
time: EventTime,
|
||||||
image: Option<String>,
|
image: Option<String>,
|
||||||
banner_data: Option<BannerData>,
|
banner_data: Option<BannerData>,
|
||||||
color: Option<Color>,
|
color: Option<Color>,
|
||||||
|
@ -49,31 +57,62 @@ struct Code {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_current_events_from_document(doc: &str) -> Vec<Event> {
|
fn get_current_events_from_document(doc: &str) -> Vec<Event> {
|
||||||
|
let events = get_all_events(doc);
|
||||||
|
|
||||||
|
let current_time = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time no longer works").as_secs() as i64;
|
||||||
|
events.into_iter().filter(|p| match p.time.start {
|
||||||
|
None => true,
|
||||||
|
Some(start) => {
|
||||||
|
start <= current_time && match p.time.end {
|
||||||
|
None => true,
|
||||||
|
Some(end) => current_time < end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_upcoming_events_from_document(doc: &str) -> Vec<Event> {
|
||||||
|
let events = get_all_events(doc);
|
||||||
|
|
||||||
|
let current_time = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time no longer works").as_secs() as i64;
|
||||||
|
events.into_iter().filter(|p| match p.time.start {
|
||||||
|
None => false,
|
||||||
|
Some(start) => {
|
||||||
|
start > current_time && match p.time.end {
|
||||||
|
None => true,
|
||||||
|
Some(end) => current_time < end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_all_events(doc: &str) -> Vec<Event> {
|
||||||
let document = Document::from(doc);
|
let document = Document::from(doc);
|
||||||
let nodes = document.find(Class("event-tracker")).collect::<Vec<Node>>();
|
let nodes = document.find(Class("event-tracker")).collect::<Vec<Node>>();
|
||||||
let event_nodes = nodes.get(0);
|
let mut events: Vec<Event> = vec![];
|
||||||
|
|
||||||
let mut events : Vec<Event> = vec![];
|
|
||||||
|
|
||||||
parse_events(&doc, event_nodes, &mut events);
|
|
||||||
|
|
||||||
|
let current_event_nodes = nodes.get(0);
|
||||||
|
parse_events(&doc, current_event_nodes, &mut events);
|
||||||
|
let upcoming_event_nodes = nodes.get(1);
|
||||||
|
parse_events(&doc, upcoming_event_nodes, &mut events);
|
||||||
events
|
events
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn parse_events(doc: &&str, event_nodes: Option<&Node>, events: &mut Vec<Event>) {
|
fn parse_events(doc: &&str, event_nodes: Option<&Node>, events: &mut Vec<Event>) {
|
||||||
if let Some(x) = event_nodes {
|
if let Some(x) = event_nodes {
|
||||||
for event in x.find(Class("accordion-item")) {
|
for event in x.find(Class("accordion-item")) {
|
||||||
let mut attributes = event.attr("class").expect("").split(' ');
|
let mut attributes = event.attr("class").expect("Cant find class attribute").split(' ');
|
||||||
if attributes.clone().count() != 2 { continue; }
|
if attributes.clone().count() != 2 { continue; }
|
||||||
|
|
||||||
|
|
||||||
let name = event.find(Class("event-name")).next().expect("Cannot find name").text();
|
let name = event.find(Class("event-name")).next().expect("Cannot find name").text();
|
||||||
|
|
||||||
let (image, color) = get_image_color(&doc, &mut attributes);
|
let (image, color) = get_image_color(doc, &mut attributes);
|
||||||
|
|
||||||
let description = get_description(event);
|
let description = get_description(event);
|
||||||
|
|
||||||
let time = event.find(Class("time")).next().map(|x| x.text());
|
let time = get_time(event);
|
||||||
|
|
||||||
let event_type = get_event_type(event, &description);
|
let event_type = get_event_type(event, &description);
|
||||||
|
|
||||||
|
@ -84,16 +123,30 @@ fn parse_events(doc: &&str, event_nodes: Option<&Node>, events: &mut Vec<Event>)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_upcoming_events_from_document(doc: &str) -> Vec<Event> {
|
|
||||||
let document = Document::from(doc);
|
|
||||||
let nodes = document.find(Class("event-tracker")).collect::<Vec<Node>>();
|
|
||||||
let event_nodes = nodes.get(1);
|
|
||||||
let mut events : Vec<Event> = vec![];
|
|
||||||
|
|
||||||
parse_events(&doc, event_nodes, &mut events);
|
fn get_date(date_string: &str) -> Option<String> {
|
||||||
events
|
let date_regex = Regex::new(r"(?m)[0-9]{4}/(?:1[0-9]|0[1-9])/(?:0[1-9]|[1-2][0-9]|3[0-1]) (?:(?:[01][0-9]|2[0-3])|[0-9]):[0-5][0-9]").expect("Cannot compile time regex");
|
||||||
|
date_regex.captures(date_string).map(|x| x.get(0).expect("No captures found").as_str().to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_time(event: Node) -> EventTime {
|
||||||
|
event.find(Class("duration")).next().map(|x| {
|
||||||
|
let text = x.text();
|
||||||
|
let dates = Regex::new(r" [-–] ").expect("Can't create split time regex").split(text.as_str()).collect::<Vec<&str>>();
|
||||||
|
let start_date_text = dates.first().expect("Cannot get start date string").to_owned();
|
||||||
|
let end_date_text = dates.get(1).expect("Cannot get end date string").to_owned();
|
||||||
|
let start = get_date(start_date_text).map(|x| {
|
||||||
|
NaiveDateTime::parse_from_str(x.as_str(), "%Y/%m/%d %H:%M").expect("Date").timestamp()
|
||||||
|
});
|
||||||
|
let end = get_date(end_date_text).map(|x| {
|
||||||
|
NaiveDateTime::parse_from_str(x.as_str(), "%Y/%m/%d %H:%M").expect("Date").timestamp()
|
||||||
|
});
|
||||||
|
|
||||||
|
EventTime {start, end}
|
||||||
|
}).expect("No time found")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fn get_codes_from_document(doc: &str) -> Option<Vec<Code>> {
|
fn get_codes_from_document(doc: &str) -> Option<Vec<Code>> {
|
||||||
let document = Document::from(doc);
|
let document = Document::from(doc);
|
||||||
document.find(Class("codes")).next().map( |codes | {
|
document.find(Class("codes")).next().map( |codes | {
|
||||||
|
@ -125,7 +178,7 @@ fn get_description(event: Node) -> Option<(String, String)> {
|
||||||
let description = event.find(Class("description")).next().map(|x| {
|
let description = event.find(Class("description")).next().map(|x| {
|
||||||
let text = x.text();
|
let text = x.text();
|
||||||
let desc = text.split(": ").collect::<Vec<&str>>();
|
let desc = text.split(": ").collect::<Vec<&str>>();
|
||||||
(desc.first().expect("").to_string(), desc.get(1).expect("").to_string())
|
(desc.first().expect("Cannot get description title").to_string(), desc.get(1).expect("Cannot get description text").to_string())
|
||||||
});
|
});
|
||||||
description
|
description
|
||||||
}
|
}
|
||||||
|
@ -163,7 +216,7 @@ fn get_event_type(event: Node, description: &Option<(String, String)>) -> EventT
|
||||||
fn get_banner_data(event: Node) -> Option<BannerData> {
|
fn get_banner_data(event: Node) -> Option<BannerData> {
|
||||||
let five_stars = event.find(Class("rarity-5").descendant(Name("picture")).descendant(Name("img"))).next().map(|x| x.attr("alt").expect("No alt on five star image").to_string());
|
let five_stars = event.find(Class("rarity-5").descendant(Name("picture")).descendant(Name("img"))).next().map(|x| x.attr("alt").expect("No alt on five star image").to_string());
|
||||||
let four_stars = event.find(Class("rarity-4")).take(3).map(|four_stars_node| {
|
let four_stars = event.find(Class("rarity-4")).take(3).map(|four_stars_node| {
|
||||||
four_stars_node.find(Name("picture").descendant(Name("img"))).next().map(|x| x.attr("alt").expect("No alt on four star image").to_string()).expect("")
|
four_stars_node.find(Name("picture").descendant(Name("img"))).next().map(|x| x.attr("alt").expect("No alt on four star image").to_string()).expect("Cannot get four stars names")
|
||||||
}).collect::<Vec<String>>();
|
}).collect::<Vec<String>>();
|
||||||
|
|
||||||
match five_stars {
|
match five_stars {
|
||||||
|
@ -176,7 +229,7 @@ fn get_banner_data(event: Node) -> Option<BannerData> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_current_events_embeds(doc : &str) -> Vec<CreateEmbed> {
|
fn create_current_events_embeds(doc : &str) -> Vec<CreateEmbed> {
|
||||||
let mut events = get_current_events_from_document(doc);
|
let mut events = get_current_events_from_document(doc).into_iter().take(8).collect::<Vec<Event>>();
|
||||||
|
|
||||||
events.sort_by(sort_events());
|
events.sort_by(sort_events());
|
||||||
|
|
||||||
|
@ -193,8 +246,8 @@ fn create_current_events_embeds(doc : &str) -> Vec<CreateEmbed> {
|
||||||
embed = embed.color(color);
|
embed = embed.color(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(time) = event.time {
|
if let Some(time) = event.time.end {
|
||||||
embed = embed.description(format!("Time remaining : {}", time));
|
embed = embed.description(format!("Ends <t:{}:R>", time));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(description) = event.description {
|
if let Some(description) = event.description {
|
||||||
|
@ -217,17 +270,16 @@ fn create_upcoming_embed(doc : &str) -> Option<CreateEmbed> {
|
||||||
events.sort_by(sort_events());
|
events.sort_by(sort_events());
|
||||||
if events.is_empty() {return None;}
|
if events.is_empty() {return None;}
|
||||||
|
|
||||||
let banner_events : Vec<Event> = events.to_vec().into_iter().filter(|p| matches!(p.event_type, EventType::ConeBanner | EventType::CharacterBanner)).collect();
|
let banner_events : Vec<Event> = events.iter().cloned().filter(|p| matches!(p.event_type, EventType::ConeBanner | EventType::CharacterBanner)).collect();
|
||||||
|
let other_events: Vec<Event> = events.iter().cloned().filter(|p| !matches!(p.event_type, EventType::ConeBanner | EventType::CharacterBanner)).rev().collect();
|
||||||
let other_events: Vec<Event> = events.iter().cloned().filter(|p| !matches!(p.event_type, EventType::ConeBanner | EventType::CharacterBanner)).collect();
|
|
||||||
|
|
||||||
Some(CreateEmbed::default()
|
Some(CreateEmbed::default()
|
||||||
.title("Upcoming Events")
|
.title("Upcoming Events")
|
||||||
.field("Banners", banner_events.iter().map(|banner| {
|
.field("Banners", banner_events.iter().map(|banner| {
|
||||||
format!("{} - **{}** : Starts in {}", banner.name, banner.banner_data.as_ref().expect("").five_stars, banner.time.as_ref().expect(""))
|
format!("{} - **{}** : Starts <t:{}:R>", banner.name, banner.banner_data.as_ref().expect("No Banner Data on Banner").five_stars, banner.time.start.expect("No start time for Upcomming Event"))
|
||||||
}).collect::<Vec<String>>().join("\n"),false)
|
}).collect::<Vec<String>>().join("\n"),false)
|
||||||
.field("Events", other_events.iter().map(|event| {
|
.field("Events", other_events.iter().map(|event| {
|
||||||
format!("{} : Starts in {}", event.name, event.time.as_ref().expect(""))
|
format!("{} : Starts <t:{}:R>", event.name, event.time.start.expect("No start time for Upcomming Event"))
|
||||||
}).collect::<Vec<String>>().join("\n"),false)
|
}).collect::<Vec<String>>().join("\n"),false)
|
||||||
.color(Color::from_rgb(rand::random(), rand::random(), rand::random()))
|
.color(Color::from_rgb(rand::random(), rand::random(), rand::random()))
|
||||||
.footer(|f| f.text("Data from https://www.prydwen.gg"))
|
.footer(|f| f.text("Data from https://www.prydwen.gg"))
|
||||||
|
@ -245,6 +297,7 @@ fn create_codes_embed(doc : &str) -> Option<CreateEmbed> {
|
||||||
false => format!("- {}", code.code)
|
false => format!("- {}", code.code)
|
||||||
}
|
}
|
||||||
}).collect::<Vec<String>>().join("\n"))
|
}).collect::<Vec<String>>().join("\n"))
|
||||||
|
.url("https://hsr.hoyoverse.com/gift")
|
||||||
.color(Color::from_rgb(rand::random(), rand::random(), rand::random()))
|
.color(Color::from_rgb(rand::random(), rand::random(), rand::random()))
|
||||||
.footer(|f| f.text("Data from https://www.prydwen.gg"))
|
.footer(|f| f.text("Data from https://www.prydwen.gg"))
|
||||||
.to_owned())
|
.to_owned())
|
||||||
|
@ -253,6 +306,7 @@ fn create_codes_embed(doc : &str) -> Option<CreateEmbed> {
|
||||||
|
|
||||||
pub async fn create_event_embeds() -> Vec<CreateEmbed> {
|
pub async fn create_event_embeds() -> Vec<CreateEmbed> {
|
||||||
let doc = get_main_prydwen().await;
|
let doc = get_main_prydwen().await;
|
||||||
|
|
||||||
let mut embeds: Vec<CreateEmbed> = vec![];
|
let mut embeds: Vec<CreateEmbed> = vec![];
|
||||||
embeds.append(create_current_events_embeds(&doc).as_mut());
|
embeds.append(create_current_events_embeds(&doc).as_mut());
|
||||||
if let Some(embed) = create_upcoming_embed(&doc) {
|
if let Some(embed) = create_upcoming_embed(&doc) {
|
||||||
|
@ -281,7 +335,17 @@ fn sort_events() -> fn(&Event, &Event) -> Ordering {
|
||||||
(EventType::Other, EventType::ConeBanner) => Ordering::Greater,
|
(EventType::Other, EventType::ConeBanner) => Ordering::Greater,
|
||||||
(EventType::ConeBanner, EventType::CharacterBanner) => Ordering::Greater,
|
(EventType::ConeBanner, EventType::CharacterBanner) => Ordering::Greater,
|
||||||
|
|
||||||
(_, _) => { Ordering::Equal }
|
(_, _) => {
|
||||||
|
match (a.time.end, b.time.end) {
|
||||||
|
(Some(a_end), Some(b_end)) => {
|
||||||
|
match a_end > b_end {
|
||||||
|
true => Ordering::Greater,
|
||||||
|
false => Ordering::Less
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Ordering::Equal
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -294,7 +358,7 @@ pub async fn create_event_message(
|
||||||
#[description = "Create Event Tab"] channel: Channel
|
#[description = "Create Event Tab"] channel: Channel
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
|
|
||||||
let message = get_discord_status_message(ctx.guild().expect("").id.0).await;
|
let message = get_discord_status_message(ctx.guild().expect("Message not sent in guild").id.0).await;
|
||||||
if let Some(e) = message {
|
if let Some(e) = message {
|
||||||
let rm = ChannelId::from(e.channel_id as u64)
|
let rm = ChannelId::from(e.channel_id as u64)
|
||||||
.message(&ctx.http(), MessageId::from(e.message_id as u64))
|
.message(&ctx.http(), MessageId::from(e.message_id as u64))
|
||||||
|
|
|
@ -3,13 +3,17 @@ mod data;
|
||||||
mod utils;
|
mod utils;
|
||||||
mod mongo;
|
mod mongo;
|
||||||
|
|
||||||
|
use std::any::Any;
|
||||||
|
use std::fmt::Display;
|
||||||
|
use std::hash::Hash;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
use poise::FrameworkError;
|
||||||
use poise::serenity_prelude::GatewayIntents;
|
use poise::serenity_prelude::GatewayIntents;
|
||||||
use serenity::client::Context;
|
use serenity::client::Context;
|
||||||
use serenity::model::id::ChannelId;
|
use serenity::model::id::ChannelId;
|
||||||
use serenity::model::prelude::Activity;
|
use serenity::model::prelude::Activity;
|
||||||
use crate::commands::events::create_event_embeds;
|
use crate::commands::events::create_event_embeds;
|
||||||
use crate::data::{Data};
|
use crate::data::{Data, Error};
|
||||||
use crate::mongo::core::get_all_status_messages;
|
use crate::mongo::core::get_all_status_messages;
|
||||||
|
|
||||||
fn update_daily(ctx: Context) {
|
fn update_daily(ctx: Context) {
|
||||||
|
|
Loading…
Reference in a new issue