i added so much that its hard to remember what i added.
This commit is contained in:
@@ -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"] }
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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()
|
||||
Reference in New Issue
Block a user