i decided i wanted to compress the embed JSON... and fix some bugs :3

This commit is contained in:
2025-06-10 23:02:46 +02:00
parent 20d906c3ba
commit e4bb754ef0
9 changed files with 55 additions and 18 deletions
+2
View File
@@ -6,7 +6,9 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
base64 = "0.22.1"
clap = { version = "4.5.28", features = ["derive"] } clap = { version = "4.5.28", features = ["derive"] }
flate2 = "1.1.2"
formatx = "0.2.3" formatx = "0.2.3"
futures = "0.3.31" futures = "0.3.31"
poise = "0.6.1" poise = "0.6.1"
+38 -4
View File
@@ -1,7 +1,13 @@
use std::env; use std::env;
use std::io::{Read, Write};
use crate::{lang, Args, Context}; use crate::{lang, Args, Context};
use base64::engine::general_purpose;
use base64::Engine;
use flate2::read::ZlibDecoder;
use flate2::write::ZlibEncoder;
use flate2::Compression;
use poise::serenity_prelude::json::Value; use poise::serenity_prelude::json::Value;
use poise::{serenity_prelude::CreateMessage, CreateReply, ReplyHandle}; use poise::{serenity_prelude::CreateMessage, CreateReply, ReplyHandle};
use poise::serenity_prelude::{ChannelId, Color, CreateActionRow, CreateButton, CreateEmbed, CreateEmbedAuthor, EditMessage, Http, Message, ReactionType, Timestamp, UserId}; use poise::serenity_prelude::{ChannelId, Color, CreateActionRow, CreateButton, CreateEmbed, CreateEmbedAuthor, EditMessage, Http, Message, ReactionType, Timestamp, UserId};
@@ -47,7 +53,7 @@ impl Default for EmbedOptions {
static DEFAULT_DC_COL: u32 = 5793266; static DEFAULT_DC_COL: u32 = 5793266;
static REMOVED_DC_COL: u32 = 16716032; static REMOVED_DC_COL: u32 = 16716032;
pub static JSON_TEXT_START: &str = "-# JSON: ||`"; pub static JSON_TEXT_START: &str = "-# Data: ||`";
pub static JSON_TEXT_END: &str = "`||"; pub static JSON_TEXT_END: &str = "`||";
@@ -230,12 +236,13 @@ pub fn make_post_embed(post_data: &Value, url: &str, ephemeral: bool) -> EmbedOp
.join("\n"); .join("\n");
let media_urls = post_data["post_data"]["media_urls"].as_array().unwrap(); let media_urls = post_data["post_data"]["media_urls"].as_array().unwrap();
let action_row = make_post_components(); let action_row = make_post_components();
let json_encoded = trim_compress_and_encode_json(post_data);
return EmbedOptions { return EmbedOptions {
title: Some(post_data["post_data"]["title"].as_str().unwrap().to_string()), title: Some(post_data["post_data"]["title"].as_str().unwrap().to_string()),
desc: format!("{}\n\n{}{}{}", trimmed, JSON_TEXT_START, serde_json::to_string(&post_data).unwrap(), JSON_TEXT_END), desc: format!("{}\n\n{}{}{}", trimmed, JSON_TEXT_START, json_encoded, JSON_TEXT_END),
col: Some(DEFAULT_DC_COL), col: Some(DEFAULT_DC_COL),
url: Some(url.to_string()), url: Some(url.to_string()),
ts: Some(Timestamp::from_unix_timestamp(post_data["post_data"]["date_unix"].as_i64().unwrap()).unwrap()), ts: Some(Timestamp::from_unix_timestamp(post_data["post_data"]["date_unix"].as_i64().unwrap()).unwrap()),
@@ -262,9 +269,11 @@ pub fn make_removed_embed(post_data: &Value, url: &str, ephemeral: bool) -> Embe
url url
); );
let json_encoded = trim_compress_and_encode_json(post_data);
return EmbedOptions { return EmbedOptions {
title: Some(lang!("dc_msg_removed_square_brackets", post_data["post_data"]["title"].clone())), title: Some(lang!("dc_msg_removed_square_brackets", post_data["post_data"]["title"].clone())),
desc: format!("{}\n\n{}{}{}", desc, JSON_TEXT_START, serde_json::to_string(&post_data).unwrap(), JSON_TEXT_END), desc: format!("{}\n\n{}{}{}", desc, JSON_TEXT_START, json_encoded, JSON_TEXT_END),
col: Some(REMOVED_DC_COL), col: Some(REMOVED_DC_COL),
url: Some(url.to_string()), url: Some(url.to_string()),
ts: Some(Timestamp::from_unix_timestamp(post_data["post_data"]["date_unix"].as_i64().unwrap()).unwrap()), ts: Some(Timestamp::from_unix_timestamp(post_data["post_data"]["date_unix"].as_i64().unwrap()).unwrap()),
@@ -275,6 +284,31 @@ pub fn make_removed_embed(post_data: &Value, url: &str, ephemeral: bool) -> Embe
} }
pub fn trim_post_json(j: &Value) -> Value {
let mut json_trimmed = j.clone();
json_trimmed["post_data"].as_object_mut().unwrap().remove("media_urls");
return json_trimmed;
}
pub fn trim_compress_and_encode_json(j: &Value) -> String {
let trim = trim_post_json(j);
let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default());
encoder.write_all(serde_json::to_string(&trim).unwrap().as_bytes()).unwrap();
let compressed = encoder.finish().unwrap();
return general_purpose::STANDARD.encode(&compressed);
}
pub fn decode_and_decompress_json(t: String) -> Result<Value, serde_json::Error> {
let compressed = general_purpose::STANDARD.decode(t).unwrap();
let mut decoder = ZlibDecoder::new(&compressed[..]);
let mut decompressed = String::new();
decoder.read_to_string(&mut decompressed).unwrap();
return serde_json::from_str(&decompressed);
}
fn make_post_components() -> CreateActionRow { fn make_post_components() -> CreateActionRow {
return CreateActionRow::Buttons(vec![ return CreateActionRow::Buttons(vec![
CreateButton::new("vote_btn") .label(lang!("dc_btn_vote")) .emoji(ReactionType::Unicode("⬆️".to_string())), CreateButton::new("vote_btn") .label(lang!("dc_btn_vote")) .emoji(ReactionType::Unicode("⬆️".to_string())),
+1 -1
View File
@@ -21,7 +21,7 @@ pub async fn cmd(
#[description = "Wether to approve it after adding it"] approve: Option<bool> #[description = "Wether to approve it after adding it"] approve: Option<bool>
) -> Result<(), Error> ) -> Result<(), Error>
{ {
if is_bk_mod_msg(ctx).await { return Ok(()); } if !is_bk_mod_msg(ctx).await { return Ok(()); }
let shorturl_u = to_shorturl(&url); let shorturl_u = to_shorturl(&url);
let shorturl = &shorturl_u.unwrap_or(url.clone()); let shorturl = &shorturl_u.unwrap_or(url.clone());
+2 -2
View File
@@ -18,7 +18,7 @@ pub async fn cmd(
#[description = "Wether to approve or disapprove the post"] disapprove: Option<bool> #[description = "Wether to approve or disapprove the post"] disapprove: Option<bool>
) -> Result<(), Error> ) -> Result<(), Error>
{ {
if is_bk_mod_msg(ctx).await { return Ok(()); } if !is_bk_mod_msg(ctx).await { return Ok(()); }
data::update_re_data(ctx.data()).await; data::update_re_data(ctx.data()).await;
let reddit_data = get_mutex_data(&ctx.data().reddit_data).await?; let reddit_data = get_mutex_data(&ctx.data().reddit_data).await?;
@@ -31,7 +31,7 @@ pub async fn cmd(
async fn approve_cmd(ctx: Context<'_>, url: &str, reddit_data: &Value, approve: bool) { async fn approve_cmd(ctx: Context<'_>, url: &str, reddit_data: &Value, approve: bool) {
if let Some(post) = reddit_data.get(CFG_DATA_RE).unwrap().get(url) { if let Some(post) = reddit_data.get(CFG_DATA_RE).unwrap().get(url) {
if post.get("removed").is_some() { if post["removed"]["removed"].as_bool().unwrap() {
send_embed_for_removed(ctx, url, post).await; send_embed_for_removed(ctx, url, post).await;
return; return;
} }
+3 -4
View File
@@ -2,7 +2,7 @@ use poise::serenity_prelude::{self as serenity, ChannelId, ComponentInteraction,
use regex::Regex; use regex::Regex;
use serde_json::Value; use serde_json::Value;
use crate::{data::get_toml_mutex, lang, messages::{embed_from_options, make_post_embed, make_removed_embed, send_embed, send_msg, EmbedOptions, JSON_TEXT_END, JSON_TEXT_START}, Context, Data, Error}; use crate::{data::get_toml_mutex, lang, messages::{decode_and_decompress_json, embed_from_options, make_post_embed, make_removed_embed, send_embed, send_msg, EmbedOptions, JSON_TEXT_END, JSON_TEXT_START}, Context, Data, Error};
pub fn is_bk_mod(mod_list: Vec<u64>, uid: u64) -> bool { pub fn is_bk_mod(mod_list: Vec<u64>, uid: u64) -> bool {
return mod_list.contains(&uid); return mod_list.contains(&uid);
@@ -14,7 +14,7 @@ pub async fn is_bk_mod_msg(ctx: Context<'_>) -> bool {
let sr = get_readable_subreddits(ctx.data()).await.unwrap(); let sr = get_readable_subreddits(ctx.data()).await.unwrap();
send_msg(ctx, lang!("dc_msg_re_permdeny_not_re_mod", sr), false, false).await; send_msg(ctx, lang!("dc_msg_re_permdeny_not_re_mod", sr), false, false).await;
return true return false
} }
@@ -85,6 +85,5 @@ pub fn embed_to_json(embed: &Embed) -> Result<Value, serde_json::Error> {
let msg_last_len = msg_lines.clone().last().unwrap().len(); let msg_last_len = msg_lines.clone().last().unwrap().len();
let msg_json_str = &msg_lines.clone().last().unwrap()[JSON_TEXT_START.len()..msg_last_len - JSON_TEXT_END.len()]; let msg_json_str = &msg_lines.clone().last().unwrap()[JSON_TEXT_START.len()..msg_last_len - JSON_TEXT_END.len()];
let msg_json: Result<Value, serde_json::Error> = serde_json::from_str(msg_json_str); return decode_and_decompress_json(msg_json_str.to_string());
return msg_json;
} }
+1 -1
View File
@@ -16,7 +16,7 @@ pub async fn cmd(
#[description = "The reason of the removal."] reason: Option<String> #[description = "The reason of the removal."] reason: Option<String>
) -> Result<(), Error> ) -> Result<(), Error>
{ {
if is_bk_mod_msg(ctx).await { return Ok(()); } if !is_bk_mod_msg(ctx).await { return Ok(()); }
let auth = &ctx.author().name; let auth = &ctx.author().name;
let r = send_cmd_json("remove_post_url", Some(json!([&url, &auth, &reason])), true).await.unwrap(); let r = send_cmd_json("remove_post_url", Some(json!([&url, &auth, &reason])), true).await.unwrap();
+1 -1
View File
@@ -34,7 +34,7 @@ pub async fn cmd(
let posts_u = posts.as_object().unwrap(); let posts_u = posts.as_object().unwrap();
for (url, dat) in posts_u { for (url, dat) in posts_u {
if dat.get("removed").is_some() { continue; } if dat["removed"]["removed"].as_bool().unwrap() { continue; }
let val: i32 = match category { let val: i32 = match category {
TopCategory::Upvotes => dat["post_data"]["upvotes"].as_i64().unwrap() as i32, TopCategory::Upvotes => dat["post_data"]["upvotes"].as_i64().unwrap() as i32,
+6 -4
View File
@@ -3,7 +3,7 @@ use std::time::{SystemTime, UNIX_EPOCH};
use poise::{serenity_prelude::{ChannelId, EditMessage, GetMessages, Http, Message, MessageId, UserId}, ReplyHandle}; use poise::{serenity_prelude::{ChannelId, EditMessage, GetMessages, Http, Message, MessageId, UserId}, ReplyHandle};
use serde_json::{json, Map, Value}; use serde_json::{json, Map, Value};
use crate::{data::{self, get_mutex_data, DC_POSTS_CHANNEL_KEY}, lang, messages::{edit_reply, embed_from_options, make_post_embed, make_removed_embed, send_embed, send_msg}, re_cmds::generic_fns::embed_to_json, rs_println, websocket::send_cmd_json, Context, Error, CFG_DATA_RE}; use crate::{data::{self, get_mutex_data, DC_POSTS_CHANNEL_KEY}, lang, messages::{edit_reply, embed_from_options, make_post_embed, make_removed_embed, send_embed, send_msg, trim_post_json}, re_cmds::generic_fns::embed_to_json, rs_println, websocket::send_cmd_json, Context, Error, CFG_DATA_RE};
#[poise::command( #[poise::command(
slash_command, slash_command,
@@ -14,7 +14,7 @@ use crate::{data::{self, get_mutex_data, DC_POSTS_CHANNEL_KEY}, lang, messages::
guild_cooldown = 120, guild_cooldown = 120,
required_bot_permissions = "SEND_MESSAGES | VIEW_CHANNEL | READ_MESSAGE_HISTORY | EMBED_LINKS" required_bot_permissions = "SEND_MESSAGES | VIEW_CHANNEL | READ_MESSAGE_HISTORY | EMBED_LINKS"
)] )]
/// Updates the binded Discord channel with the bot's current Reddit data. /// Updates the bound Discord channel with the bot's current Reddit data.
pub async fn cmd( pub async fn cmd(
ctx: Context<'_>, ctx: Context<'_>,
#[description = "Only adds new posts, leaves everything else unchanged."] #[description = "Only adds new posts, leaves everything else unchanged."]
@@ -182,6 +182,8 @@ async fn msgs_to_json(msgs: Vec<Message>, reddit_data: &Value, max_age: u64) ->
let u_json: Value = msg_json.unwrap(); let u_json: Value = msg_json.unwrap();
let re_url = &reddit_data[CFG_DATA_RE][&url]; let re_url = &reddit_data[CFG_DATA_RE][&url];
let json_trimmed = trim_post_json(re_url);
let post_date = re_url["post_data"]["date_unix"].as_u64().unwrap_or(0); let post_date = re_url["post_data"]["date_unix"].as_u64().unwrap_or(0);
// old // old
@@ -194,7 +196,7 @@ async fn msgs_to_json(msgs: Vec<Message>, reddit_data: &Value, max_age: u64) ->
} }
// removed // removed
if re_url["removed"]["removed"].as_bool().unwrap() { if json_trimmed["removed"]["removed"].as_bool().unwrap() {
if u_json["removed"]["removed"].as_bool().unwrap() { if u_json["removed"]["removed"].as_bool().unwrap() {
// no change // no change
if let Some(obj) = msgs_json["no_change"].as_object_mut() { if let Some(obj) = msgs_json["no_change"].as_object_mut() {
@@ -211,7 +213,7 @@ async fn msgs_to_json(msgs: Vec<Message>, reddit_data: &Value, max_age: u64) ->
} }
// updated // updated
if &u_json != re_url if u_json != json_trimmed
{ {
if let Some(obj) = msgs_json["updated"].as_object_mut() { if let Some(obj) = msgs_json["updated"].as_object_mut() {
obj.insert(url.clone(), json!(msg.id.get())); obj.insert(url.clone(), json!(msg.id.get()));
+1 -1
View File
@@ -26,7 +26,7 @@ pub async fn cmd(
send_msg(ctx, lang!("dc_msg_re_post_404"), false, false).await; send_msg(ctx, lang!("dc_msg_re_post_404"), false, false).await;
return Ok(()); return Ok(());
} }
if post_data[&url].get("removed").is_some() { if post_data[&url]["removed"]["removed"].as_bool().unwrap() {
send_embed_for_removed(ctx, &url, &post_data[&url]).await; send_embed_for_removed(ctx, &url, &post_data[&url]).await;
return Ok(()); return Ok(());
} }