Skip to content

Commit

Permalink
Merge pull request #103 from ItsGamerik/issue-82
Browse files Browse the repository at this point in the history
add autodownload
  • Loading branch information
ItsGamerik authored Jan 10, 2024
2 parents 3d0e569 + 669e4a2 commit 545a3aa
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 39 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "get-img"
version = "0.2.1"
version = "0.3.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand Down
34 changes: 21 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
## Description

Index attachments and messages (including threads!) in a discord channel or an entire server with a simple command and save the content to a file.
Once you have indexed messages, you can download the message list with a command and you can also automatically download all of the attachments that were uploaded to your computer!
Once you have indexed messages, you can download the message list with a command, and you can also automatically download all the attachments that were uploaded to your computer!

## Usage

### Building

just use [cargo](https://www.rust-lang.org/tools/install) for building:
just use [cargo](https://www.rust-lang.org/tools/install) (the rust building utility) for building:

```shell
cargo build --release && cargo run --release
Expand All @@ -22,28 +22,30 @@ cargo build --release && cargo run --release
First, set your Discord bot token as an environment variable:

```shell
export DISCORD_TOKEN=""
export DISCORD_TOKEN="<your_token_here>"
```

pro tip: make sure to put a space before the "export" to hide the command from your history.
pro-tip: make sure to put a space before the "export" to hide the command from your history.

on windows you can use the
on windows, you can use the

```powershell
$ENV:DISCORD_TOKEN=""
$ENV:DISCORD_TOKEN="<your_token_here>"
```

command to set your environment variable.

**You will have to do the same for the `GUILD_ID` environment variable so the bot can register all the commands to your Discord server.**

### Commands

```text
/help displays the help message
/index [channel] index every message with an attachment in a channel.
/download [bool] sends the index file into the discord channel, and will download attachments if specified.
/watch [channel] [bool] toggles the automatic indexing for the specified channel on and off.
/indexall index all messages of the server where the interaction was sent. Due to API limitations, this can take quite a long time, especially for larger servers. Progress is indicated by the bot's status.
```
| Command | Usage |
|--------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| /help | displays the help message. |
| /index [channel] | index every message with an attachment in a channel. |
| /watch [channel] [bool] [bool] | toggles the automatic indexing for the specified channel on and off. Can also automatically download the attachments to disk if toggled on (optional). |
| /download [bool] | sends the index file into the discord channel, and will download attachments if specified. |
| /indexall | index all messages of the server where the interaction was sent. Due to API limitations, this can take quite a long time, especially for larger servers. Progress is indicated by the bot's status. |

you have to be an administrator of the discord server you are using the bot in to be able to use the commands:

Expand All @@ -55,6 +57,12 @@ you have to be an administrator of the discord server you are using the bot in t

- /indexall

### Docker

(this still requires some editing)

Docker images are available [here](https://hub.docker.com/r/gamerik/get-img)

## Setting up a bot through Discord

1. Go to the [Discord Developer page](https://discord.com/developers/applications).
Expand Down
18 changes: 14 additions & 4 deletions src/commands/download.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ use std::path::{Path, PathBuf};
use log::{error, info};
use regex::Regex;
use serenity::all::CommandOptionType::Boolean;
use serenity::all::{ActivityData, CommandInteraction, Context, CreateAttachment, CreateCommand, CreateCommandOption, CreateInteractionResponseFollowup, OnlineStatus, Permissions, ResolvedOption, ResolvedValue};
use serenity::all::{
ActivityData, CommandInteraction, Context, CreateAttachment, CreateCommand,
CreateCommandOption, CreateInteractionResponseFollowup, OnlineStatus, Permissions,
ResolvedOption, ResolvedValue,
};
use tokio::fs::File;
use tokio::io::{AsyncBufReadExt, AsyncWriteExt};
use tokio::{fs, io};
Expand Down Expand Up @@ -48,7 +52,10 @@ pub async fn run(ctx: Context, interaction: &CommandInteraction, options: &[Reso
)
.await
.unwrap();
ctx.set_presence(Some(ActivityData::watching("Ready to go :D")), OnlineStatus::Online);
ctx.set_presence(
Some(ActivityData::watching("Ready to go :D")),
OnlineStatus::Online,
);
} else {
// if it is false
interaction
Expand All @@ -60,7 +67,10 @@ pub async fn run(ctx: Context, interaction: &CommandInteraction, options: &[Reso
)
.await
.unwrap();
ctx.set_presence(Some(ActivityData::watching("Ready to go :D")), OnlineStatus::Online);
ctx.set_presence(
Some(ActivityData::watching("Ready to go :D")),
OnlineStatus::Online,
);
}
} else {
followup_status_message(
Expand Down Expand Up @@ -91,7 +101,7 @@ async fn read_file() {
}
}

async fn download_file(url: String) {
pub async fn download_file(url: String) {
let client = reqwest::Client::new();
let response = match client.get(&url).send().await {
Ok(r) => r,
Expand Down
2 changes: 1 addition & 1 deletion src/commands/help.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub async fn run(ctx: Context, interaction: &CommandInteraction) {
.field("`/help`", "shows this message", false)
.field("`/index`", "index every message with an attachment in a channel", false)
.field("`/download`", "sends the index file into the discord channel, and will download attachments if specified.", false)
.field("`/watch`", "toggles the automatic indexing for the specified channel on and off.", false)
.field("`/watch`", "toggles the automatic indexing for the specified channel on and off. Can also automatically download the attachments to disk if toggled on (optional).", false)
.field("`/indexall`", "index all messages of the server where the interaction was sent. Due to API limitations, this can take quite a long time, especially for larger servers. Progress is indicated by the bot's status.", false)
.url("https://github.com/ItsGamerik/get-img#commands").color(Colour::DARK_GREEN);

Expand Down
97 changes: 79 additions & 18 deletions src/commands/watch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::error::Error;
use std::fs::OpenOptions;
use std::io::Write;

use log::{error, info};
use log::{error, info, warn};
use serde::{Deserialize, Serialize};
use serenity::all::{
ChannelId, CommandInteraction, CommandOptionType, Context, CreateCommand, CreateCommandOption,
Expand All @@ -17,11 +17,13 @@ use crate::helper_functions::{edit_status_message, status_message};
pub struct WatcherEntry {
pub id: ChannelId,
pub creator: UserId,
pub autodl: bool,
}

pub async fn run(ctx: Context, interaction: &CommandInteraction, options: &[ResolvedOption<'_>]) {
let option_channel: &&PartialChannel;
let option_bool: &bool;
let option_toggle: &bool;
let option_dl: &bool;

if let Some(ResolvedOption {
value: ResolvedValue::Channel(channel),
Expand All @@ -39,12 +41,23 @@ pub async fn run(ctx: Context, interaction: &CommandInteraction, options: &[Reso
..
}) = options.get(1)
{
option_bool = bool
option_toggle = bool
} else {
error!("could not parse watcher command options");
return;
}

if let Some(ResolvedOption {
value: ResolvedValue::Boolean(bool),
..
}) = options.get(2)
{
option_dl = bool
} else {
option_dl = &false;
info!("defaulting to false for watcher")
}

let mut watch_track_file = match OpenOptions::new()
.write(true)
.create(true)
Expand All @@ -60,25 +73,67 @@ pub async fn run(ctx: Context, interaction: &CommandInteraction, options: &[Reso

status_message(&ctx, "creating/updating channel watcher...", interaction).await;

if let &true = option_bool {
let watcher_entry = WatcherEntry {
id: option_channel.id,
creator: interaction.user.id,
let file2 = match File::open("./.watchers").await {
Ok(f) => f,
Err(e) => {
warn!("watcher file not found, not indexing message ({e})");
return;
}
};

let mut lines = tokio::io::BufReader::new(file2).lines();
while let Some(line) = lines.next_line().await.unwrap() {
let json: WatcherEntry = match serde_json::from_str(&line) {
Ok(entry) => entry,
Err(_) => {
info!("watch file does not exist yet");
return;
}
};
if json.id == option_channel.id {
delete_line_from_file("./.watchers", option_channel.id).await.unwrap();
}
}

let json = serde_json::to_string(&watcher_entry).unwrap();
let file = match File::open("./.watchers").await {
Ok(f) => f,
Err(e) => {
warn!("watcher file not found, not indexing message ({e})");
return;
}
};

if let Err(e) = writeln!(watch_track_file, "{json}") {
error!("an error occurred writing to file: {e}");
match (option_toggle, option_dl) {
(true, true) => {
let watcher_entry = WatcherEntry {
id: option_channel.id,
creator: interaction.user.id,
autodl: true,
};
let json = serde_json::to_string(&watcher_entry).unwrap();
if let Err(e) = writeln!(watch_track_file, "{json}") {
error!("an error occurred writing to file: {e}");
}
}
} else {
let file = File::open("./.watchers").await.unwrap();
let mut lines = BufReader::new(file).lines();
while let Some(line) = lines.next_line().await.unwrap() {
let json: WatcherEntry = serde_json::from_str(&line).unwrap();
if json.id == option_channel.id {
if let Err(e) = delete_line_from_file("./.watchers", option_channel.id).await {
error!("an error occurred writing to file: {e}")
(true, false) => {
let watcher_entry = WatcherEntry {
id: option_channel.id,
creator: interaction.user.id,
autodl: false,
};
let json = serde_json::to_string(&watcher_entry).unwrap();
if let Err(e) = writeln!(watch_track_file, "{json}") {
error!("an error occurred writing to file: {e}");
}
}
_ => {
let mut lines = BufReader::new(file).lines();
while let Some(line) = lines.next_line().await.unwrap() {
let json: WatcherEntry = serde_json::from_str(&line).unwrap();
if json.id == option_channel.id {
if let Err(e) = delete_line_from_file("./.watchers", option_channel.id).await {
error!("an error occurred writing to file: {e}")
}
}
}
}
Expand Down Expand Up @@ -131,6 +186,12 @@ pub fn register() -> CreateCommand {
"toggle watcher on and off",
)
.required(true),
CreateCommandOption::new(
CommandOptionType::Boolean,
"autodownload",
"automatically download attachments",
)
.required(false),
])
.default_member_permissions(Permissions::ADMINISTRATOR)
}
10 changes: 9 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use simple_logger::SimpleLogger;
use tokio::fs::File;
use tokio::io::AsyncBufReadExt;

use crate::commands::download::download_file;
use crate::commands::watch::WatcherEntry;
use crate::helper_functions::universal_message_writer;

Expand All @@ -25,7 +26,7 @@ impl EventHandler for Handler {
Err(e) => {
warn!("watcher file not found, not indexing message ({e})");
return;
},
}
};

let mut lines = tokio::io::BufReader::new(watcher_file).lines();
Expand All @@ -40,6 +41,13 @@ impl EventHandler for Handler {
if msg.channel_id == json.id {
info!("Channel watcher found a new message: {}", msg.id);
universal_message_writer(msg.clone()).await;
if json.autodl {
for attachment in msg.attachments.clone() {
download_file(attachment.url).await;
}
} else {
continue;
}
}
}
}
Expand Down

0 comments on commit 545a3aa

Please sign in to comment.