mirror of
https://github.com/natsukagami/youmubot.git
synced 2025-05-24 17:20:49 +00:00
Split youmubot-core
This commit is contained in:
parent
aec9cd130d
commit
84150cd82e
14 changed files with 56 additions and 38 deletions
102
youmubot-core/src/fun/images.rs
Normal file
102
youmubot-core/src/fun/images.rs
Normal file
|
@ -0,0 +1,102 @@
|
|||
use serde::Deserialize;
|
||||
use serenity::framework::standard::CommandError as Error;
|
||||
use serenity::{
|
||||
framework::standard::{
|
||||
macros::{check, command},
|
||||
Args, CheckResult, CommandOptions, CommandResult, Reason,
|
||||
},
|
||||
model::channel::{Channel, Message},
|
||||
};
|
||||
use std::string::ToString;
|
||||
use youmubot_prelude::*;
|
||||
|
||||
#[command]
|
||||
#[checks(nsfw)]
|
||||
#[description = "🖼️ Find an image with a given tag on Danbooru[nsfw]!"]
|
||||
#[min_args(1)]
|
||||
#[bucket("images")]
|
||||
pub fn nsfw(ctx: &mut Context, msg: &Message, args: Args) -> CommandResult {
|
||||
message_command(ctx, msg, args, Rating::Explicit)
|
||||
}
|
||||
|
||||
#[command]
|
||||
#[description = "🖼️ Find an image with a given tag on Danbooru[safe]!"]
|
||||
#[min_args(1)]
|
||||
#[bucket("images")]
|
||||
pub fn image(ctx: &mut Context, msg: &Message, args: Args) -> CommandResult {
|
||||
message_command(ctx, msg, args, Rating::Safe)
|
||||
}
|
||||
|
||||
#[check]
|
||||
#[name = "nsfw"]
|
||||
fn nsfw_check(ctx: &mut Context, msg: &Message, _: &mut Args, _: &CommandOptions) -> CheckResult {
|
||||
let channel = msg.channel_id.to_channel(&ctx).unwrap();
|
||||
if !(match channel {
|
||||
Channel::Guild(guild_channel) => guild_channel.read().nsfw,
|
||||
_ => true,
|
||||
}) {
|
||||
CheckResult::Failure(Reason::User("😣 YOU FREAKING PERVERT!!!".to_owned()))
|
||||
} else {
|
||||
CheckResult::Success
|
||||
}
|
||||
}
|
||||
|
||||
fn message_command(ctx: &mut Context, msg: &Message, args: Args, rating: Rating) -> CommandResult {
|
||||
let tags = args.remains().unwrap_or("touhou");
|
||||
let http = ctx.data.get_cloned::<HTTPClient>();
|
||||
let image = get_image(&http, rating, tags)?;
|
||||
match image {
|
||||
None => msg.reply(&ctx, "🖼️ No image found...\n💡 Tip: In danbooru, character names follow Japanese standards (last name before first name), so **Hakurei Reimu** might give you an image while **Reimu Hakurei** won't."),
|
||||
Some(url) => msg.reply(
|
||||
&ctx,
|
||||
format!("🖼️ Here's the image you requested!\n\n{}", url),
|
||||
),
|
||||
}?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Gets an image URL.
|
||||
fn get_image(
|
||||
client: &<HTTPClient as TypeMapKey>::Value,
|
||||
rating: Rating,
|
||||
tags: &str,
|
||||
) -> Result<Option<String>, Error> {
|
||||
// Fix the tags: change whitespaces to +
|
||||
let tags = tags.split_whitespace().collect::<Vec<_>>().join("_");
|
||||
let req = client
|
||||
.get(&format!(
|
||||
"https://danbooru.donmai.us/posts.json?tags=rating:{}+{}",
|
||||
rating.to_string(),
|
||||
tags
|
||||
))
|
||||
.query(&[("limit", "1"), ("random", "true")])
|
||||
.build()?;
|
||||
println!("{:?}", req.url());
|
||||
let response: Vec<PostResponse> = client.execute(req)?.json()?;
|
||||
Ok(response
|
||||
.into_iter()
|
||||
.next()
|
||||
.map(|v| format!("https://danbooru.donmai.us/posts/{}", v.id)))
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
struct PostResponse {
|
||||
id: u64,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
enum Rating {
|
||||
Explicit,
|
||||
Safe,
|
||||
}
|
||||
|
||||
impl ToString for Rating {
|
||||
fn to_string(&self) -> String {
|
||||
use Rating::*;
|
||||
match self {
|
||||
Explicit => "explicit",
|
||||
Safe => "safe",
|
||||
}
|
||||
.to_owned()
|
||||
}
|
||||
}
|
178
youmubot-core/src/fun/mod.rs
Normal file
178
youmubot-core/src/fun/mod.rs
Normal file
|
@ -0,0 +1,178 @@
|
|||
use rand::{
|
||||
distributions::{Distribution, Uniform},
|
||||
thread_rng,
|
||||
};
|
||||
use serenity::{
|
||||
framework::standard::{
|
||||
macros::{command, group},
|
||||
Args, CommandResult,
|
||||
},
|
||||
model::{channel::Message, id::UserId},
|
||||
utils::MessageBuilder,
|
||||
};
|
||||
use youmubot_prelude::*;
|
||||
|
||||
mod images;
|
||||
mod names;
|
||||
|
||||
use images::*;
|
||||
|
||||
#[group]
|
||||
#[description = "Random commands"]
|
||||
#[commands(roll, pick, name, image, nsfw)]
|
||||
struct Fun;
|
||||
|
||||
#[command]
|
||||
#[description = "🎲 Rolls a dice that gives you a random number."]
|
||||
#[min_args(0)]
|
||||
#[max_args(2)]
|
||||
#[usage = "[max-dice-faces = 6] / [message]"]
|
||||
#[example = "100 / What's my score?"]
|
||||
fn roll(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResult {
|
||||
let dice = if args.is_empty() {
|
||||
6
|
||||
} else {
|
||||
args.single::<u64>()?
|
||||
};
|
||||
|
||||
if dice == 0 {
|
||||
msg.reply(&ctx, "Give me a dice with 0 faces, what do you expect 😒")?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let result = {
|
||||
let dice_rng = Uniform::from(1..=dice);
|
||||
let mut rng = thread_rng();
|
||||
dice_rng.sample(&mut rng)
|
||||
};
|
||||
|
||||
match args.single_quoted::<String>() {
|
||||
Ok(s) => msg.reply(
|
||||
&ctx,
|
||||
MessageBuilder::new()
|
||||
.push("you asked ")
|
||||
.push_bold_safe(s)
|
||||
.push(format!(
|
||||
", so I rolled a 🎲 of **{}** faces, and got **{}**!",
|
||||
dice, result
|
||||
))
|
||||
.build(),
|
||||
),
|
||||
Err(_) if args.is_empty() => msg.reply(
|
||||
&ctx,
|
||||
format!(
|
||||
"I rolled a 🎲 of **{}** faces, and got **{}**!",
|
||||
dice, result
|
||||
),
|
||||
),
|
||||
Err(e) => return Err(e.into()),
|
||||
}?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[command]
|
||||
#[description = r#"👈 Pick a choice from the available list of choices.
|
||||
You may prefix the first choice with `?` to make it a question!
|
||||
If no choices are given, Youmu defaults to `Yes!` and `No!`"#]
|
||||
#[usage = "[?question]/[choice #1]/[choice #2]/..."]
|
||||
#[example = "?What for dinner/Pizza/Hamburger"]
|
||||
fn pick(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResult {
|
||||
let (question, choices) = {
|
||||
// Get a list of options.
|
||||
let mut choices = args
|
||||
.quoted()
|
||||
.trimmed()
|
||||
.iter::<String>()
|
||||
.map(|v| v.unwrap())
|
||||
.peekable();
|
||||
// If we have the first argument as question, use it.
|
||||
let question = match choices.peek() {
|
||||
Some(ref q) if q.starts_with("?") => Some(q.replacen("?", "", 1) + "?"),
|
||||
_ => None,
|
||||
};
|
||||
// If we have a question, that's not a choice.
|
||||
let mut choices = match question {
|
||||
Some(_) => {
|
||||
choices.next();
|
||||
choices
|
||||
}
|
||||
None => choices,
|
||||
};
|
||||
// If there are no choices, default to Yes! and No!
|
||||
let choices = match choices.peek() {
|
||||
None => vec!["Yes!".to_owned(), "No!".to_owned()],
|
||||
_ => choices.collect(),
|
||||
};
|
||||
(question, choices)
|
||||
};
|
||||
|
||||
let choice = {
|
||||
let uniform = Uniform::from(0..choices.len());
|
||||
let mut rng = thread_rng();
|
||||
&choices[uniform.sample(&mut rng)]
|
||||
};
|
||||
|
||||
match question {
|
||||
None => msg.reply(
|
||||
&ctx,
|
||||
MessageBuilder::new()
|
||||
.push("Youmu picks 👉")
|
||||
.push_bold_safe(choice)
|
||||
.push("👈!")
|
||||
.build(),
|
||||
),
|
||||
Some(s) => msg.reply(
|
||||
&ctx,
|
||||
MessageBuilder::new()
|
||||
.push("you asked ")
|
||||
.push_bold_safe(s)
|
||||
.push(", and Youmu picks 👉")
|
||||
.push_bold_safe(choice)
|
||||
.push("👈!")
|
||||
.build(),
|
||||
),
|
||||
}?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[command]
|
||||
#[description = "Wanna know what your name is in Japanese🇯🇵?"]
|
||||
#[usage = "[user_mention = yourself]"]
|
||||
#[example = "@user#1234"]
|
||||
#[max_args(1)]
|
||||
fn name(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResult {
|
||||
let user_id = if args.is_empty() {
|
||||
msg.author.id
|
||||
} else {
|
||||
args.single::<UserId>()?
|
||||
};
|
||||
|
||||
let user_mention = if user_id == msg.author.id {
|
||||
"your".to_owned()
|
||||
} else {
|
||||
MessageBuilder::new()
|
||||
.push_bold_safe(user_id.to_user(&ctx)?.tag())
|
||||
.push("'s")
|
||||
.build()
|
||||
};
|
||||
|
||||
// Rule out a couple of cases
|
||||
if user_id == ctx.http.get_current_application_info()?.id {
|
||||
// This is my own user_id
|
||||
msg.reply(&ctx, "😠 My name is **Youmu Konpaku**!")?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let (first_name, last_name) = names::name_from_userid(user_id);
|
||||
|
||||
msg.reply(
|
||||
&ctx,
|
||||
format!(
|
||||
"{} Japanese🇯🇵 name is **{} {}**!",
|
||||
user_mention, first_name, last_name
|
||||
),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
1547
youmubot-core/src/fun/names.rs
Normal file
1547
youmubot-core/src/fun/names.rs
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue