diff --git a/TODO.md b/TODO.md index 1efd833..c0aa6e4 100644 --- a/TODO.md +++ b/TODO.md @@ -1,10 +1,10 @@ ### High priority: - [x] ~~Embed creation tool~~ - [ ] Reddit bot that scrapes images with tag "Original Art" and posts them in Discord server - - [ ] Discord bot /bk_help command + - [x] ~~Discord bot /bk_help command~~ - [x] ~~Scrape the data~~ - [x] ~~Put it in a JSON~~ - - [ ] Multithread so it can run both Discord and Reddit bot!!! + - [x] ~~Multithread so it can run both Discord and Reddit bot!!!~~ - [ ] Ship Python data to Rust - [ ] Allow updating the data autonomously and via manual commands. - [ ] Manually add posts (via `u/[bot] add` or `/bk_week_add [url]`) @@ -26,7 +26,7 @@ - [ ] BPS args -> JSON - [ ] Random tip (from ByteDice.net/data/loadingScreenTips.json) - [ ] A command that just sends my socials -- [x] Magic 8 ball +- [x] ~~Magic 8 ball~~ ### Low priority: - [ ] Particle of the week diff --git a/bk_week_help.txt b/bk_week_help.txt new file mode 100644 index 0000000..3c494f4 --- /dev/null +++ b/bk_week_help.txt @@ -0,0 +1,46 @@ +``` +--- Discord commands --- +/bk_week_add [url] [approve] - Takes a URL and adds it to the list of posts. + This is done automatically by the bot for certain posts. + [approve] is true or false, and determines wether to pre- + approve the post. +/bk_week_remove [url] - Takes an existing URL and removes it from the list of posts. +/bk_week_approve [url] - Takes an existing URL and flags the post as human_approved. + Approve a post to tell the bot that an art piece is original art. +/bk_week_disapprove [url] - Does what /bk_week_approve does, but opposite. + +EXAMPLES: +/bk_week_add https://reddit.com/abc123 false +/bk_week_approve https://reddit.com/def456 + +--- Reddit commands --- +To execute a command on the Reddit bot, type "u/ByteDiceAssistant [args]" in a comment. +[args] should be replaced with a command: + +add - Adds the post the command was ran in to the list of posts. + +EXAMPLES: +u/ByteDiceAssistant add + +You can even do this: (without the quotes) + """ + Hey guys welcome back to my lets play, today we are checking out original art. + Wow, this art is original and cool. + + u/ByteDiceAssistant add + + I want this art to be recognized + """ +and this: + "Cool art. u/ByteDiceAssistant add +and this: + """ + Cool art. u/ByteDiceAssistant add + Very cool. + """ + +But you cant do this: (without the quotes) + "Cool art. u/ByteDiceAssistant add very cool." + "Cool art. u/ByteDiceAssistant add. Very cool." + "Cool art. u/ByteDiceAssistant add." (Notice the period?) +``` \ No newline at end of file diff --git a/src/cmds.rs b/src/cmds.rs index 6eced3f..d85e099 100644 --- a/src/cmds.rs +++ b/src/cmds.rs @@ -1,7 +1,9 @@ use crate::{Context, Error}; use crate::messages::{send_embed, send_msg, edit_msg, EmbedOptions}; -use poise::serenity_prelude::{GetMessages, OnlineStatus, Timestamp}; +use std::fs; + +use poise::serenity_prelude::{GetMessages, OnlineStatus, Timestamp, UserId}; use rand::{seq::IteratorRandom, Rng}; @@ -27,13 +29,18 @@ pub async fn stop( let should_stop = dev_enabled || confirmation.unwrap_or_else(|| "".to_string()).to_lowercase() == "i want to stop the bot now"; - if should_stop { + let is_creator = ctx.author().id == UserId::new(ctx.data().creator_id); + + if should_stop && is_creator { send_msg(ctx, "Shutting down...".to_string(), true, true).await; ctx.serenity_context().set_presence(None, OnlineStatus::Invisible); ctx.framework().shard_manager.shutdown_all().await; } - else { - send_msg(ctx, "Failed to shut down.".to_string(), true, true).await; + else if !is_creator { + send_msg(ctx, "Failed to shut down: Invalid permissions.".to_string(), true, true).await; + } + else if !should_stop { + send_msg(ctx, "Failed to shut down: Invalid confirmation.".to_string(), true, true).await; } return Ok(()); @@ -209,5 +216,17 @@ pub async fn rule( _rule: Vec ) -> Result<(), Error> { + return Ok(()); +} + + +#[poise::command(slash_command, prefix_command)] +pub async fn bk_week_help( + ctx: Context<'_>, +) -> Result<(), Error> +{ + let help = fs::read_to_string("./bk_week_help.txt").unwrap(); + send_msg(ctx, help, true, true).await; + return Ok(()); } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 0632f41..4c3c086 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,17 +3,19 @@ mod events; mod messages; mod python; -use poise::serenity_prelude::Client; use std::env; use std::process; use std::thread; use std::fs; +use tokio::runtime::Runtime; +use poise::serenity_prelude::Client; use poise::serenity_prelude as serenity; struct Data { dev: bool, - ball_prompts: [Vec; 2] + ball_prompts: [Vec; 2], + creator_id: u64 } type Error = Box; type Context<'a> = poise::Context<'a, Data, Error>; @@ -21,7 +23,7 @@ type Context<'a> = poise::Context<'a, Data, Error>; #[macro_export] macro_rules! rs_println { ($($arg:tt)*) => { - println!("RS - {}", format!($($arg)*)); + println!("RS - {}", format!($($arg)*)); }; } @@ -42,22 +44,26 @@ async fn main() { { println!("----- PYTHON ONLY MODE -----"); let _ = python::start(); - process::exit(1); + process::exit(0); } else if args.contains(&"--rs".to_string()) && ! args.contains(&"--py".to_string()) { println!("----- RUST ONLY MODE -----"); start(args).await; - process::exit(1); + process::exit(0); } - let rust = thread::spawn(|| { + let rt = Runtime::new().unwrap(); + let rust = thread::spawn(move || { + rt.block_on(async { + start(args).await; + }); }); let python = thread::spawn(|| { - + let _ = python::start(); }); rust.join().unwrap(); @@ -69,7 +75,7 @@ async fn start(args: Vec) { let data = gen_data(args); let mut bot = gen_bot(data).await; - println!("Starting bot..."); + rs_println!("Starting bot..."); bot.start().await.unwrap(); } @@ -83,7 +89,8 @@ fn gen_data(args: Vec) -> Data { return Data { dev: args.contains(&"--dev".to_string()), - ball_prompts: [ball_classic, ball_quirk] + ball_prompts: [ball_classic, ball_quirk], + creator_id: 697149665166229614, }; } @@ -95,7 +102,7 @@ async fn gen_bot(data: Data) -> Client { let peek_len = 27; let token_peek = &token[..peek_len]; let token_end_len = token[peek_len..].len(); - println!("Token: {}{}", token_peek, "*".repeat(token_end_len)); + rs_println!("Token: {}{}", token_peek, "*".repeat(token_end_len)); let framework = poise::Framework::builder() @@ -106,7 +113,8 @@ async fn gen_bot(data: Data) -> Client { cmds::stop(), cmds::eight_ball(), cmds::write_json(), - cmds::rule() + cmds::rule(), + cmds::bk_week_help() ], event_handler: events::event_handler, ..Default::default() diff --git a/src/messages.rs b/src/messages.rs index 3ede786..9a6e21a 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -1,4 +1,4 @@ -use crate::Context; +use crate::{rs_println, Context}; use poise::{serenity_prelude::CreateMessage, CreateReply, ReplyHandle}; use poise::serenity_prelude::{Color, CreateEmbed, Timestamp}; @@ -61,6 +61,8 @@ pub async fn send_embed( reply: bool ) -> Option> { + let r_text = format!("Sent embed: {}", options.title.clone().unwrap_or_else(|| "No title".to_string())); + let mut embed = CreateEmbed::new() .title (none_to_empty(options.title)) .description(options.desc) @@ -77,11 +79,13 @@ pub async fn send_embed( }; let msg = ctx.send(r).await; + rs_println!("{}", r_text); return Some(msg.unwrap()); } else { let r = CreateMessage::new().embeds(vec![embed]); let _ = ctx.channel_id().send_message(ctx.http(), r).await; + rs_println!("{}", r_text); return None; } } @@ -93,9 +97,12 @@ pub async fn edit_msg( new_text: String ) { let r = CreateReply { - content: Some(new_text), + content: Some(new_text.clone()), ..Default::default() }; let _ = msg.edit(ctx, r).await; + + let msg_text = &msg.message().await.unwrap().content; + rs_println!("Edited message: {} -> {}", msg_text, new_text); } \ No newline at end of file diff --git a/src/python.rs b/src/python.rs index 28e20d6..15ebd8f 100644 --- a/src/python.rs +++ b/src/python.rs @@ -2,9 +2,10 @@ use crate::rs_println; use std::fs; use std::ffi::CString; +use std::env; + use pyo3::prelude::*; use pyo3::types::PyList; -use std::env; pub fn start() -> PyResult<()> { @@ -16,6 +17,7 @@ pub fn start() -> PyResult<()> { let app_path = CString::new(code).unwrap(); pyo3::prepare_freethreaded_python(); + let from_python = Python::with_gil(|py| -> PyResult> { let syspath = py .import("sys")?