i added so much that its hard to remember what i added.

This commit is contained in:
2025-02-05 19:23:49 +01:00
parent 04a0efcfd7
commit 3f2c628830
9 changed files with 226 additions and 132 deletions
+1
View File
@@ -7,6 +7,7 @@ edition = "2021"
[dependencies]
poise = "0.6.1"
pyo3 = "0.23.4"
rand = "0.9.0"
serde_json = "1.0.138"
tokio = { version = "1.43.0", features = ["rt-multi-thread"] }
+3 -2
View File
@@ -4,7 +4,8 @@
- [ ] Discord bot /bk_help command
- [x] ~~Scrape the data~~
- [x] ~~Put it in a JSON~~
- [ ] Ship it to Discord using the Rust bot
- [ ] 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]`)
- [ ] Manually remove posts (via `/bk_week_remove [url]`)
@@ -13,7 +14,7 @@
- [x] ~~Automatically add scraped posts to JSON~~
- [ ] Automatically remove posts older than 7 days from JSON
- [x] ~~Function~~
- [ ] Autonomize
- [ ] Automate
- [ ] Automatically approve posts that dont get caught by reverse image search (ris)
### Medium priority:
+13
View File
@@ -0,0 +1,13 @@
--- Run command ---
cargo run [-- {options}]
Examples:
cargo run
cargo run -- --dev
cargo run -- --py --dev
--- Options: ---
--h, --help - View this text.
--dev - Run in dev mode. Disables certain security measures.
--rs - Only run the Rust portion of the program.
--py - Only run the Python portion of the program.
+2 -1
View File
@@ -1,4 +1,5 @@
use crate::{send_embed, send_msg, edit_msg, Context, EmbedOptions, Error};
use crate::{Context, Error};
use crate::messages::{send_embed, send_msg, edit_msg, EmbedOptions};
use poise::serenity_prelude::{GetMessages, OnlineStatus, Timestamp};
use rand::{seq::IteratorRandom, Rng};
+1 -5
View File
@@ -9,7 +9,7 @@ pub fn event_handler<'a>(
ctx: &'a serenity::Context,
event: &'a serenity::FullEvent,
_framework: poise::FrameworkContext<'a, Data, Error>,
data: &'a Data,
_data: &'a Data,
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'a>> {
Box::pin(async move {
if let serenity::FullEvent::Ready { data_about_bot } = event {
@@ -19,10 +19,6 @@ pub fn event_handler<'a>(
data_about_bot.user.id
);
if data.dev {
println!("----- DEV MODE ENABLED -----");
}
let file_text = std::fs::read_to_string("./data/status.txt").unwrap();
let custom_activity = ActivityData::custom(file_text);
// TODO: make custom rich presence
+48 -116
View File
@@ -1,13 +1,15 @@
mod cmds;
mod events;
mod messages;
mod python;
use poise::{serenity_prelude::{Client, CreateMessage}, CreateReply, ReplyHandle};
use core::str;
use poise::serenity_prelude::Client;
use std::env;
use std::process::Command;
use std::process;
use std::thread;
use std::fs;
use poise::serenity_prelude::{self as serenity, Color, CreateEmbed, Timestamp};
use poise::serenity_prelude as serenity;
struct Data {
dev: bool,
@@ -16,26 +18,11 @@ struct Data {
type Error = Box<dyn std::error::Error + Send + Sync>;
type Context<'a> = poise::Context<'a, Data, Error>;
struct EmbedOptions {
desc: String,
title: Option<String>,
col: Option<u32>,
url: Option<String>,
ts: Option<Timestamp>,
empheral: bool
}
impl Default for EmbedOptions {
fn default() -> Self {
return EmbedOptions {
desc: "default description".to_string(),
title: None,
col: None,
url: None,
ts: None,
empheral: false
};
}
#[macro_export]
macro_rules! rs_println {
($($arg:tt)*) => {
println!("RS - {}", format!($($arg)*));
};
}
@@ -43,27 +30,47 @@ impl Default for EmbedOptions {
async fn main() {
let args: Vec<String> = env::args().collect();
if args.contains(&"--py".to_string()) {
let output = Command::new("python")
.arg("./src/python/main.py")
.output()
.expect("Failed to launch main.py");
let stdout = str::from_utf8(&output.stdout).unwrap_or("Invalid UTF-8 in stdout");
let stderr = str::from_utf8(&output.stderr).unwrap_or("Invalid UTF-8 in stderr");
println!("--- PYTHON OUTPUT:\n\n{}\n", stdout);
println!("--- PYTHON ERROR:\n\n{}", stderr);
if args.contains(&"--h".to_string()) || args.contains(&"--help".to_string()) {
let help = fs::read_to_string("./help.txt").unwrap_or_else(|_| "No help.txt file found.".to_string());
println!("HELP MENU:\n{}", help);
process::exit(1);
}
else {
let data = gen_data(args);
let mut bot = gen_bot(data).await;
println!("Starting bot...");
bot.start().await.unwrap();
if args.contains(&"--py".to_string())
&& !args.contains(&"--rs".to_string())
{
println!("----- PYTHON ONLY MODE -----");
let _ = python::start();
process::exit(1);
}
else if args.contains(&"--rs".to_string())
&& ! args.contains(&"--py".to_string())
{
println!("----- RUST ONLY MODE -----");
start(args).await;
process::exit(1);
}
if args.contains(&"--dev".to_string()) { println!("----- DEV MODE ENABLED -----"); }
let rust = thread::spawn(|| {
});
let python = thread::spawn(|| {
});
rust.join().unwrap();
python.join().unwrap();
}
async fn start(args: Vec<String>) {
let data = gen_data(args);
let mut bot = gen_bot(data).await;
println!("Starting bot...");
bot.start().await.unwrap();
}
@@ -116,79 +123,4 @@ async fn gen_bot(data: Data) -> Client {
.framework(framework)
.await
.unwrap();
}
fn none_to_empty(string: Option<String>) -> String {
return string.unwrap_or_else(|| "".to_string());
}
async fn send_msg(
ctx: Context<'_>,
t: String,
empheral: bool,
reply: bool
) -> Option<ReplyHandle<'_>>
{
if reply {
let r = CreateReply {
content: Some(t),
ephemeral: Some(empheral),
..Default::default()
};
let msg = ctx.send(r).await;
return Some(msg.unwrap());
}
else {
let _ = ctx.channel_id().say(ctx.http(), t).await;
return None;
}
}
async fn send_embed(
ctx: Context<'_>,
options: EmbedOptions,
reply: bool
) -> Option<ReplyHandle<'_>>
{
let mut embed = CreateEmbed::new()
.title (none_to_empty(options.title))
.description(options.desc)
.colour (Color::new(options.col.unwrap_or_else(|| 5793266)))
.url (none_to_empty(options.url));
if options.ts.is_some() { embed = embed.timestamp(options.ts.unwrap()); }
if reply {
let r = CreateReply {
embeds: vec![embed],
ephemeral: Some(options.empheral),
..Default::default()
};
let msg = ctx.send(r).await;
return Some(msg.unwrap());
}
else {
let r = CreateMessage::new().embeds(vec![embed]);
let _ = ctx.channel_id().send_message(ctx.http(), r).await;
return None;
}
}
async fn edit_msg(
ctx: Context<'_>,
msg: ReplyHandle<'_>,
new_text: String
) {
let r = CreateReply {
content: Some(new_text),
..Default::default()
};
let _ = msg.edit(ctx, r).await;
}
+101
View File
@@ -0,0 +1,101 @@
use crate::Context;
use poise::{serenity_prelude::CreateMessage, CreateReply, ReplyHandle};
use poise::serenity_prelude::{Color, CreateEmbed, Timestamp};
pub struct EmbedOptions {
pub desc: String,
pub title: Option<String>,
pub col: Option<u32>,
pub url: Option<String>,
pub ts: Option<Timestamp>,
pub empheral: bool
}
impl Default for EmbedOptions {
fn default() -> Self {
return EmbedOptions {
desc: "default description".to_string(),
title: None,
col: None,
url: None,
ts: None,
empheral: false
};
}
}
fn none_to_empty(string: Option<String>) -> String {
return string.unwrap_or_else(|| "".to_string());
}
pub async fn send_msg(
ctx: Context<'_>,
t: String,
empheral: bool,
reply: bool
) -> Option<ReplyHandle<'_>>
{
if reply {
let r = CreateReply {
content: Some(t),
ephemeral: Some(empheral),
..Default::default()
};
let msg = ctx.send(r).await;
return Some(msg.unwrap());
}
else {
let _ = ctx.channel_id().say(ctx.http(), t).await;
return None;
}
}
pub async fn send_embed(
ctx: Context<'_>,
options: EmbedOptions,
reply: bool
) -> Option<ReplyHandle<'_>>
{
let mut embed = CreateEmbed::new()
.title (none_to_empty(options.title))
.description(options.desc)
.colour (Color::new(options.col.unwrap_or_else(|| 5793266)))
.url (none_to_empty(options.url));
if options.ts.is_some() { embed = embed.timestamp(options.ts.unwrap()); }
if reply {
let r = CreateReply {
embeds: vec![embed],
ephemeral: Some(options.empheral),
..Default::default()
};
let msg = ctx.send(r).await;
return Some(msg.unwrap());
}
else {
let r = CreateMessage::new().embeds(vec![embed]);
let _ = ctx.channel_id().send_message(ctx.http(), r).await;
return None;
}
}
pub async fn edit_msg(
ctx: Context<'_>,
msg: ReplyHandle<'_>,
new_text: String
) {
let r = CreateReply {
content: Some(new_text),
..Default::default()
};
let _ = msg.edit(ctx, r).await;
}
+43
View File
@@ -0,0 +1,43 @@
use crate::rs_println;
use std::fs;
use std::ffi::CString;
use pyo3::prelude::*;
use pyo3::types::PyList;
use std::env;
pub fn start() -> PyResult<()> {
rs_println!("Running Python program...");
let path = concat!(env!("CARGO_MANIFEST_DIR"), "\\src\\python");
let code = get_code(&(path.to_owned() + "\\main.py"));
let app_path = CString::new(code).unwrap();
pyo3::prepare_freethreaded_python();
let from_python = Python::with_gil(|py| -> PyResult<Py<PyAny>> {
let syspath = py
.import("sys")?
.getattr("path")?
.downcast_into::<PyList>()?;
syspath.insert(0, path)?;
let empty = CString::new("").unwrap();
let app: Py<PyAny> = PyModule::from_code(py, &app_path, &empty, &empty)?
.getattr("run")?
.into();
return app.call0(py);
});
println!("py: {}", from_python?);
return Ok(());
}
fn get_code(path: &str) -> String {
return fs::read_to_string(path)
.expect("Failed to read Python file.")
.to_string();
}
+14 -8
View File
@@ -1,7 +1,13 @@
from praw import models
def py_print(*args: str):
print("Py -", " ".join(args))
py_print("Importing external modules...")
import emoji
import sys
py_print("Importing internal modules")
import bot as botPy
import data
import reddit
@@ -11,22 +17,22 @@ def main():
sys.stdout.reconfigure(encoding="utf-8")
bot = botPy.Bot()
print("Reading data...")
py_print("Reading data...")
data.read_data(bot)
check_emoji = emoji.emojize(":check_mark_button:")
cross_emoji = emoji.emojize(":cross_mark:")
print("Fetching posts...")
py_print("Fetching posts...")
posts = reddit.fetch_posts_with_flair(bot, "Original Art")
print("Evaluating posts...\n\n")
py_print("Evaluating posts...\n\n")
for post in posts:
media = reddit.has_media(post)
media_urls = "\n ".join(media[3])
print(
f"{post.title}",
py_print(
f"\n{post.title}",
f"\n {post.shortlink}"
f"\n {check_emoji if media[0] else cross_emoji} Media ({media[1]}) [{media[2]}]",
f"\n {media_urls}\n"
@@ -48,5 +54,5 @@ def main():
data.write_data(bot)
if __name__ == "__main__":
main()
py_print("Running main()...")
main()