i added so much that its hard to remember what i added.
This commit is contained in:
@@ -7,6 +7,7 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
poise = "0.6.1"
|
poise = "0.6.1"
|
||||||
|
pyo3 = "0.23.4"
|
||||||
rand = "0.9.0"
|
rand = "0.9.0"
|
||||||
serde_json = "1.0.138"
|
serde_json = "1.0.138"
|
||||||
tokio = { version = "1.43.0", features = ["rt-multi-thread"] }
|
tokio = { version = "1.43.0", features = ["rt-multi-thread"] }
|
||||||
|
|||||||
@@ -4,7 +4,8 @@
|
|||||||
- [ ] Discord bot /bk_help command
|
- [ ] Discord bot /bk_help command
|
||||||
- [x] ~~Scrape the data~~
|
- [x] ~~Scrape the data~~
|
||||||
- [x] ~~Put it in a JSON~~
|
- [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.
|
- [ ] Allow updating the data autonomously and via manual commands.
|
||||||
- [ ] Manually add posts (via `u/[bot] add` or `/bk_week_add [url]`)
|
- [ ] Manually add posts (via `u/[bot] add` or `/bk_week_add [url]`)
|
||||||
- [ ] Manually remove posts (via `/bk_week_remove [url]`)
|
- [ ] Manually remove posts (via `/bk_week_remove [url]`)
|
||||||
@@ -13,7 +14,7 @@
|
|||||||
- [x] ~~Automatically add scraped posts to JSON~~
|
- [x] ~~Automatically add scraped posts to JSON~~
|
||||||
- [ ] Automatically remove posts older than 7 days from JSON
|
- [ ] Automatically remove posts older than 7 days from JSON
|
||||||
- [x] ~~Function~~
|
- [x] ~~Function~~
|
||||||
- [ ] Autonomize
|
- [ ] Automate
|
||||||
- [ ] Automatically approve posts that dont get caught by reverse image search (ris)
|
- [ ] Automatically approve posts that dont get caught by reverse image search (ris)
|
||||||
|
|
||||||
### Medium priority:
|
### 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 poise::serenity_prelude::{GetMessages, OnlineStatus, Timestamp};
|
||||||
use rand::{seq::IteratorRandom, Rng};
|
use rand::{seq::IteratorRandom, Rng};
|
||||||
|
|||||||
+1
-5
@@ -9,7 +9,7 @@ pub fn event_handler<'a>(
|
|||||||
ctx: &'a serenity::Context,
|
ctx: &'a serenity::Context,
|
||||||
event: &'a serenity::FullEvent,
|
event: &'a serenity::FullEvent,
|
||||||
_framework: poise::FrameworkContext<'a, Data, Error>,
|
_framework: poise::FrameworkContext<'a, Data, Error>,
|
||||||
data: &'a Data,
|
_data: &'a Data,
|
||||||
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'a>> {
|
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'a>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
if let serenity::FullEvent::Ready { data_about_bot } = event {
|
if let serenity::FullEvent::Ready { data_about_bot } = event {
|
||||||
@@ -19,10 +19,6 @@ pub fn event_handler<'a>(
|
|||||||
data_about_bot.user.id
|
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 file_text = std::fs::read_to_string("./data/status.txt").unwrap();
|
||||||
let custom_activity = ActivityData::custom(file_text);
|
let custom_activity = ActivityData::custom(file_text);
|
||||||
// TODO: make custom rich presence
|
// TODO: make custom rich presence
|
||||||
|
|||||||
+44
-112
@@ -1,13 +1,15 @@
|
|||||||
mod cmds;
|
mod cmds;
|
||||||
mod events;
|
mod events;
|
||||||
|
mod messages;
|
||||||
|
mod python;
|
||||||
|
|
||||||
use poise::{serenity_prelude::{Client, CreateMessage}, CreateReply, ReplyHandle};
|
use poise::serenity_prelude::Client;
|
||||||
use core::str;
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::process::Command;
|
|
||||||
use std::process;
|
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 {
|
struct Data {
|
||||||
dev: bool,
|
dev: bool,
|
||||||
@@ -16,55 +18,60 @@ struct Data {
|
|||||||
type Error = Box<dyn std::error::Error + Send + Sync>;
|
type Error = Box<dyn std::error::Error + Send + Sync>;
|
||||||
type Context<'a> = poise::Context<'a, Data, Error>;
|
type Context<'a> = poise::Context<'a, Data, Error>;
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
struct EmbedOptions {
|
macro_rules! rs_println {
|
||||||
desc: String,
|
($($arg:tt)*) => {
|
||||||
title: Option<String>,
|
println!("RS - {}", format!($($arg)*));
|
||||||
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
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
|
|
||||||
if args.contains(&"--py".to_string()) {
|
if args.contains(&"--h".to_string()) || args.contains(&"--help".to_string()) {
|
||||||
let output = Command::new("python")
|
let help = fs::read_to_string("./help.txt").unwrap_or_else(|_| "No help.txt file found.".to_string());
|
||||||
.arg("./src/python/main.py")
|
println!("HELP MENU:\n{}", help);
|
||||||
.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);
|
|
||||||
|
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
|
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 data = gen_data(args);
|
||||||
let mut bot = gen_bot(data).await;
|
let mut bot = gen_bot(data).await;
|
||||||
|
|
||||||
println!("Starting bot...");
|
println!("Starting bot...");
|
||||||
bot.start().await.unwrap();
|
bot.start().await.unwrap();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn gen_data(args: Vec<String>) -> Data {
|
fn gen_data(args: Vec<String>) -> Data {
|
||||||
@@ -117,78 +124,3 @@ async fn gen_bot(data: Data) -> Client {
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.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();
|
||||||
|
}
|
||||||
+13
-7
@@ -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 emoji
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
py_print("Importing internal modules")
|
||||||
|
|
||||||
import bot as botPy
|
import bot as botPy
|
||||||
import data
|
import data
|
||||||
import reddit
|
import reddit
|
||||||
@@ -11,22 +17,22 @@ def main():
|
|||||||
sys.stdout.reconfigure(encoding="utf-8")
|
sys.stdout.reconfigure(encoding="utf-8")
|
||||||
|
|
||||||
bot = botPy.Bot()
|
bot = botPy.Bot()
|
||||||
print("Reading data...")
|
py_print("Reading data...")
|
||||||
data.read_data(bot)
|
data.read_data(bot)
|
||||||
|
|
||||||
check_emoji = emoji.emojize(":check_mark_button:")
|
check_emoji = emoji.emojize(":check_mark_button:")
|
||||||
cross_emoji = emoji.emojize(":cross_mark:")
|
cross_emoji = emoji.emojize(":cross_mark:")
|
||||||
|
|
||||||
print("Fetching posts...")
|
py_print("Fetching posts...")
|
||||||
posts = reddit.fetch_posts_with_flair(bot, "Original Art")
|
posts = reddit.fetch_posts_with_flair(bot, "Original Art")
|
||||||
|
|
||||||
print("Evaluating posts...\n\n")
|
py_print("Evaluating posts...\n\n")
|
||||||
for post in posts:
|
for post in posts:
|
||||||
media = reddit.has_media(post)
|
media = reddit.has_media(post)
|
||||||
media_urls = "\n ".join(media[3])
|
media_urls = "\n ".join(media[3])
|
||||||
|
|
||||||
print(
|
py_print(
|
||||||
f"{post.title}",
|
f"\n{post.title}",
|
||||||
f"\n {post.shortlink}"
|
f"\n {post.shortlink}"
|
||||||
f"\n {check_emoji if media[0] else cross_emoji} Media ({media[1]}) [{media[2]}]",
|
f"\n {check_emoji if media[0] else cross_emoji} Media ({media[1]}) [{media[2]}]",
|
||||||
f"\n {media_urls}\n"
|
f"\n {media_urls}\n"
|
||||||
@@ -48,5 +54,5 @@ def main():
|
|||||||
data.write_data(bot)
|
data.write_data(bot)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
py_print("Running main()...")
|
||||||
main()
|
main()
|
||||||
Reference in New Issue
Block a user