First draft (need to give more customization to the user)

This commit is contained in:
winneratwin 2022-04-03 20:48:02 +01:00
commit 7a4bee227a
Signed by: winneratwin
GPG Key ID: CDBC42F8803D689E
6 changed files with 1425 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/target
/token.txt

1095
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

13
Cargo.toml Normal file
View File

@ -0,0 +1,13 @@
[package]
name = "discord-advertiser"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
reqwest = { version = "0.11", features = ["json"] }
tokio = { version = "1", features = ["full"] }
serde = { version = "1.0.136", features = ["derive"] }
serde_json = "1.0.79"
chrono = "0.4"

1
channels.txt Normal file
View File

@ -0,0 +1 @@
768990242673786950

3
message.txt Normal file
View File

@ -0,0 +1,3 @@
this is a automated
message with newlines
hi <@172716215817601026>

311
src/main.rs Normal file
View File

@ -0,0 +1,311 @@
use chrono::{DateTime, Local};
use serde::{Deserialize, Serialize};
use serde_json::json;
use std::fs::File;
use std::io::prelude::*;
use std::thread::sleep;
use std::time::Duration;
//serialise and deserialise
#[derive(Serialize, Deserialize, Debug)]
struct Message {
id: String,
content: String,
channel_id: String,
author: User,
timestamp: String,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
struct User {
id: String,
username: String,
discriminator: String,
avatar: Option<String>,
public_flags: Option<i32>,
}
#[derive(Serialize, Deserialize, Debug)]
struct Typing {
message_send_cooldown_ms: Option<i32>,
thread_create_cooldown_ms: Option<i32>,
}
#[tokio::main]
async fn main() {
// read lines from channels.txt file
let mut file = File::open("channels.txt").expect("Unable to open file");
let mut contents = String::new();
file.read_to_string(&mut contents)
.expect("Unable to read file");
let channels = contents
.trim()
.lines()
.map(|x| x.to_owned())
.collect::<Vec<String>>();
// read message from file
let mut file = File::open("message.txt").expect("Unable to open file");
let mut message = String::new();
file.read_to_string(&mut message)
.expect("Unable to read file");
// read discord token from file
let mut file = File::open("token.txt").expect("Unable to open file");
let mut token = String::new();
file.read_to_string(&mut token)
.expect("Unable to read file");
let token = token.trim().to_owned();
// get userid
let user_id = get_token_user_id(token.clone()).await;
// set delay for how long to wait before posting cringe
let delay = 60 * 15;
// create handle list for each channel
let mut handles = Vec::new();
// create a handle for each channel
for channel in channels {
// create clones of the variables to use in thread
let channel_id = channel.clone();
let message = message.clone();
let token = token.clone();
let user_id = user_id.clone();
handles.push(tokio::spawn(async move {
loop {
// check if we have sent a message in the last x minutes and more then 4 messages before our last message
let cutoff = delay;
// get current time
let current_time = Local::now();
let current_time_timestamp = current_time.timestamp();
// get last message time
let mut has_sent_message_recently = false;
let mut time_since_last_message = 0;
// set channel
let working_channel = channel_id.clone();
// get messages
let messages = get_messages(token.clone(), working_channel.clone()).await;
// get messages after our last message
let mut messages_before_last_message = 0;
//loop through messages
for message in messages {
// check if message is sent by user
if message.author.id == user_id.id {
// convert rfc 3339 timestamp to unix timestamp
// fuck discord for not using unix millis instead of rfc 3339
let timestamp =
DateTime::parse_from_rfc3339(message.timestamp.as_str()).unwrap();
// get time since message
let seconds_since_message = current_time_timestamp - timestamp.timestamp();
// check if message is sent in the last x minutes
if seconds_since_message < cutoff {
has_sent_message_recently = true;
time_since_last_message = seconds_since_message;
break;
} else {
has_sent_message_recently = false;
break;
}
} else {
// increment counter for each message before our last message
messages_before_last_message += 1;
}
}
if has_sent_message_recently {
println!(
"has sent message in the last {} minutes in {}",
cutoff/60,working_channel
);
let time_to_wait = cutoff - time_since_last_message;
sleep(Duration::from_secs(time_to_wait as u64));
}
// check if more then 5 or more messages before our last message
if messages_before_last_message < 4 {
println!(
"others have sent less then 5 messages before last message in {}",
working_channel
);
// name this loop so we can break out from it
'outer: loop {
// check every 5 minutes to see if there are more then 5 or more messages before our last message
println!(
"checking if there are more then 4 messages before our last message in {}",
working_channel
);
//count messages
let mut messages_before_last_message = 0;
for x in get_messages(token.clone(), working_channel.clone()).await {
if x.author.id == user_id.id {
if messages_before_last_message > 4 {
break 'outer;
}
}
messages_before_last_message += 1;
}
// sleep for 5 minutes
sleep(Duration::from_secs(60 * 5));
}
}
// check if we are being ratelimited by channel slowmode by using the typing endpoint(why tf is slowmode api hidden here)
let typing = get_typing(token.clone(), working_channel.clone()).await;
match typing.message_send_cooldown_ms {
Some(x) => {
let time_to_wait = x as u64;
println!(
"slowmode is active, waiting {} seconds",
time_to_wait / 1000
);
sleep(Duration::from_millis(time_to_wait));
}
None => {}
}
// send message
send_message(token.clone(), message.clone(), working_channel.clone()).await;
// sleep for delay
sleep(Duration::from_secs(cutoff as u64));
}
}));
}
println!("threads started");
for handle in handles {
match handle.await{
Ok(_) => {},
Err(e) => {
println!("{:?}", e);
}
};
}
}
async fn get_token_user_id(token: String) -> User {
let url = format!("https://discordapp.com/api/v9/users/@me");
let client = reqwest::Client::new();
let user_id = client
.get(&url)
.header("Authorization", token)
.send()
.await
.unwrap()
.json::<User>()
.await
.unwrap();
user_id
}
async fn get_messages(token: String, channel: String) -> Vec<Message> {
let mut messages: Vec<Message> = Vec::new();
let url = format!(
"https://discordapp.com/api/v9/channels/{}/messages?limit=10",
channel
);
let mut headers = reqwest::header::HeaderMap::new();
headers.insert(
"Authorization",
reqwest::header::HeaderValue::from_str(&token).unwrap(),
);
let response = reqwest::Client::new()
.get(&url)
.headers(headers)
.send()
.await
.unwrap();
let mvec = response.json::<Vec<Message>>().await.unwrap();
for x in mvec {
messages.push(x);
}
messages
}
async fn send_message(token: String, message: String, channel: String) {
//application/json
//{
// "content": message,
// "tts": false,
//}
let url = format!(
"https://discordapp.com/api/v9/channels/{}/messages",
channel
);
let client = reqwest::Client::new();
let mut headers = reqwest::header::HeaderMap::new();
headers.insert(
"Authorization",
reqwest::header::HeaderValue::from_str(&token).unwrap(),
);
headers.insert(
"Content-Type",
reqwest::header::HeaderValue::from_str("application/json").unwrap(),
);
let response = client
.post(&url)
.headers(headers)
.json(&json!({
"content": message,
"tts": false,
"allowed_mentions": {
"parse": []
}
}))
.send()
.await;
match response {
Ok(e) => {
println!("{}", e.status());
println!("{}", e.text().await.unwrap());
}
Err(e) => {
println!("{}", e);
}
}
}
async fn get_typing(token: String, channel: String) -> Typing {
let url = format!("https://discordapp.com/api/v9/channels/{}/typing", channel);
let client = reqwest::Client::new();
let mut headers = reqwest::header::HeaderMap::new();
headers.insert(
"Authorization",
reqwest::header::HeaderValue::from_str(&token).unwrap(),
);
let response = client
.post(&url)
.headers(headers)
.json(&json!({}))
.send()
.await
.unwrap();
let response_text = response.text().await.unwrap();
if response_text.len() > 0 {
let typing: Typing = serde_json::from_str(&response_text).unwrap();
typing
} else {
let typing: Typing = Typing {
message_send_cooldown_ms: None,
thread_create_cooldown_ms: None,
};
typing
}
}