parent
e91804a396
commit
ef7638a315
File diff suppressed because one or more lines are too long
@ -0,0 +1,110 @@
|
||||
use serenity::framework::standard::{macros::command, Args, CommandResult};
|
||||
use serenity::model::prelude::*;
|
||||
use serenity::prelude::*;
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use serde_json::Value;
|
||||
|
||||
use rand::seq::IteratorRandom;
|
||||
|
||||
fn random_from_string(string: &str) -> char {
|
||||
string.chars().choose(&mut rand::thread_rng()).unwrap()
|
||||
}
|
||||
|
||||
async fn display_kanji(ctx: &Context, msg: &Message, kanji: char, comment: &str) -> CommandResult {
|
||||
msg.reply(&ctx.http, format!(":game_die: {}{}", kanji, comment)).await?;
|
||||
let url = format!("https://raw.githubusercontent.com/mistval/kanji_images/master/gifs/{}.gif", format!("{:x}", kanji as i32));
|
||||
let response = reqwest::get(&url)
|
||||
.await?
|
||||
.text()
|
||||
.await?;
|
||||
msg.channel_id.say(&ctx.http, if response == "404: Not Found" {
|
||||
"The stroke order diagram for this kanji is unavailable."
|
||||
} else { &url }).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn random_kanji(category: &str, ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
|
||||
let mut lists_file = File::open("kanji_lists.json").unwrap();
|
||||
let mut lists_json = String::new();
|
||||
lists_file.read_to_string(&mut lists_json).unwrap();
|
||||
let lists_data: Value = serde_json::from_str(&lists_json).unwrap();
|
||||
let category = &lists_data[category];
|
||||
let default_version = category["default"].as_str().unwrap();
|
||||
let list = &category["versions"][default_version]["characters"];
|
||||
match list.as_str() {
|
||||
Some(string) => {
|
||||
let kanji = random_from_string(string);
|
||||
display_kanji(&ctx, &msg, kanji, "").await?;
|
||||
},
|
||||
None => {
|
||||
let subcategory = args.single::<String>();
|
||||
let subcategories = list.as_object().unwrap();
|
||||
let subcategory_list = {
|
||||
let mut string = String::from("\n");
|
||||
let mut total_count = 0;
|
||||
for subcategory in subcategories.keys() {
|
||||
let subcategory = subcategory.as_str();
|
||||
// One has to do .chars().count() as opposed to .len() here,
|
||||
// because .len() returns the byte length NOT the number of characters.
|
||||
// For kanji, they are always multi-byte Unicode characters.
|
||||
let count = &subcategories[subcategory].as_str().unwrap().chars().count();
|
||||
total_count += count;
|
||||
string.push_str(&format!("**{}** ({} kanji),\n", subcategory, count));
|
||||
}
|
||||
string.push_str(&format!("or **all** ({} kanji total) for all subcategories", total_count));
|
||||
string
|
||||
};
|
||||
match subcategory {
|
||||
Ok(string) => {
|
||||
let string = string.to_uppercase();
|
||||
if string == "ALL" {
|
||||
let subcategory_key = subcategories.keys().choose(&mut rand::thread_rng()).unwrap();
|
||||
let list = subcategories[subcategory_key].as_str().unwrap();
|
||||
let kanji = random_from_string(&list);
|
||||
display_kanji(&ctx, &msg, kanji, &format!(", **{}**", subcategory_key)).await?;
|
||||
} else if subcategories.contains_key(&string) {
|
||||
let list = list[&string].as_str().unwrap();
|
||||
let kanji = random_from_string(&list);
|
||||
display_kanji(&ctx, &msg, kanji, "").await?;
|
||||
} else {
|
||||
let message = format!("That is an invalid subcategory. Please use {}.", &subcategory_list);
|
||||
msg.reply(&ctx.http, message).await?;
|
||||
}
|
||||
},
|
||||
Err(_) => {
|
||||
let mut message = String::from("Please specify a subcategory: ");
|
||||
message.push_str(&subcategory_list);
|
||||
msg.reply(&ctx.http, message).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[command]
|
||||
async fn joyo(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
||||
random_kanji("JOYO", ctx, msg, args).await
|
||||
}
|
||||
|
||||
#[command]
|
||||
async fn jinmeiyo(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
||||
random_kanji("JINMEIYO", ctx, msg, args).await
|
||||
}
|
||||
|
||||
#[command]
|
||||
async fn kyoiku(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
||||
random_kanji("KYOIKU", ctx, msg, args).await
|
||||
}
|
||||
|
||||
#[command]
|
||||
async fn jlpt(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
||||
random_kanji("JLPT", ctx, msg, args).await
|
||||
}
|
||||
|
||||
#[command]
|
||||
async fn hyogai(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
||||
random_kanji("HYOGAI", ctx, msg, args).await
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
pub mod kanji;
|
||||
pub mod owner;
|
@ -0,0 +1,22 @@
|
||||
use serenity::framework::standard::{macros::command, CommandResult};
|
||||
use serenity::model::prelude::*;
|
||||
use serenity::prelude::*;
|
||||
|
||||
use crate::ShardManagerContainer;
|
||||
|
||||
#[command]
|
||||
#[owners_only]
|
||||
async fn sleep(ctx: &Context, msg: &Message) -> CommandResult {
|
||||
let data = ctx.data.read().await;
|
||||
|
||||
if let Some(manager) = data.get::<ShardManagerContainer>() {
|
||||
msg.reply(ctx, "Good night!").await?;
|
||||
manager.lock().await.shutdown_all().await;
|
||||
} else {
|
||||
msg.reply(ctx, "There was a problem getting the shard manager").await?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
@ -1,3 +1,102 @@
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
//! Requires the 'framework' feature flag be enabled in your project's
|
||||
//! `Cargo.toml`.
|
||||
//!
|
||||
//! This can be enabled by specifying the feature in the dependency section:
|
||||
//!
|
||||
//! ```toml
|
||||
//! [dependencies.serenity]
|
||||
//! git = "https://github.com/serenity-rs/serenity.git"
|
||||
//! features = ["framework", "standard_framework"]
|
||||
//! ```
|
||||
mod commands;
|
||||
|
||||
use std::{collections::HashSet, env, sync::Arc};
|
||||
|
||||
use commands::{kanji::*, owner::*};
|
||||
use serenity::{
|
||||
async_trait,
|
||||
client::bridge::gateway::ShardManager,
|
||||
framework::{standard::macros::group, StandardFramework},
|
||||
http::Http,
|
||||
model::{event::ResumedEvent, gateway::Ready},
|
||||
prelude::*,
|
||||
};
|
||||
use tracing::{error, info};
|
||||
|
||||
pub struct ShardManagerContainer;
|
||||
|
||||
impl TypeMapKey for ShardManagerContainer {
|
||||
type Value = Arc<Mutex<ShardManager>>;
|
||||
}
|
||||
|
||||
struct Handler;
|
||||
|
||||
#[async_trait]
|
||||
impl EventHandler for Handler {
|
||||
async fn ready(&self, _: Context, ready: Ready) {
|
||||
info!("Connected as {}", ready.user.name);
|
||||
}
|
||||
|
||||
async fn resume(&self, _: Context, _: ResumedEvent) {
|
||||
info!("Resumed");
|
||||
}
|
||||
}
|
||||
|
||||
#[group]
|
||||
#[commands(joyo, jinmeiyo, kyoiku, jlpt, hyogai, sleep)]
|
||||
struct General;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
// This will load the environment variables located at `./.env`, relative to
|
||||
// the CWD. See `./.env.example` for an example on how to structure this.
|
||||
dotenv::dotenv().expect("Failed to load .env file");
|
||||
|
||||
// Initialize the logger to use environment variables.
|
||||
//
|
||||
// In this case, a good default is setting the environment variable
|
||||
// `RUST_LOG` to `debug`.
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
let token = env::var("DISCORD_TOKEN").expect("Expected a token in the environment");
|
||||
let prefix = env::var("PREFIX").expect("Expected a prefix in the environment");
|
||||
|
||||
let http = Http::new_with_token(&token);
|
||||
|
||||
// We will fetch your bot's owners and id
|
||||
let (owners, _bot_id) = match http.get_current_application_info().await {
|
||||
Ok(info) => {
|
||||
let mut owners = HashSet::new();
|
||||
owners.insert(info.owner.id);
|
||||
|
||||
(owners, info.id)
|
||||
},
|
||||
Err(why) => panic!("Could not access application info: {:?}", why),
|
||||
};
|
||||
|
||||
// Create the framework
|
||||
let framework =
|
||||
StandardFramework::new().configure(|c| c.owners(owners).prefix(prefix)).group(&GENERAL_GROUP);
|
||||
|
||||
let mut client = Client::builder(&token)
|
||||
.framework(framework)
|
||||
.event_handler(Handler)
|
||||
.await
|
||||
.expect("Err creating client");
|
||||
|
||||
{
|
||||
let mut data = client.data.write().await;
|
||||
data.insert::<ShardManagerContainer>(client.shard_manager.clone());
|
||||
}
|
||||
|
||||
let shard_manager = client.shard_manager.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
tokio::signal::ctrl_c().await.expect("Could not register ctrl+c handler");
|
||||
shard_manager.lock().await.shutdown_all().await;
|
||||
});
|
||||
|
||||
if let Err(why) = client.start().await {
|
||||
error!("Client error: {:?}", why);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in new issue