Compare commits
2 Commits
main
...
oomer/sugg
| Author | SHA1 | Date | |
|---|---|---|---|
| 2963d5912c | |||
| 2bbf800d53 |
38
CMakeLists.txt
Normal file
38
CMakeLists.txt
Normal file
@ -0,0 +1,38 @@
|
||||
# Minimum CMake version required
|
||||
cmake_minimum_required(VERSION 3.22)
|
||||
|
||||
# Project name, version, and description
|
||||
project(discord-bot VERSION 1.0 DESCRIPTION "A discord bot" LANGUAGES CXX) # Specify CXX language
|
||||
|
||||
# Temporarily removed to rule out interference from custom CMake modules.
|
||||
# If you have custom CMake modules here that you need, we can re-add this later.
|
||||
# list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
||||
|
||||
# Create an executable
|
||||
add_executable(${PROJECT_NAME}
|
||||
src/main.cpp
|
||||
src/ImageProcessor.cpp
|
||||
)
|
||||
|
||||
# Include directories for your headers and D++ headers
|
||||
# This tells the compiler where to find #include <ImageProcessor.h> and #include <dpp/dpp.h>
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include # This covers ImageProcessor.h and the parent for dpp/dpp.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/stb # For stb_image.h and stb_image_write.h
|
||||
# Ensure this path is correct if your D++ headers are NOT directly in ${CMAKE_CURRENT_SOURCE_DIR}/include/dpp
|
||||
# If dpp/dpp.h is found in ${CMAKE_CURRENT_SOURCE_DIR}/include/dpp, then the line below is correct.
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/dpp
|
||||
)
|
||||
|
||||
# --- NEW: Direct Linker Injection using Generator Expression ---
|
||||
# This method tells CMake to ONLY pass the full path to the linker,
|
||||
# explicitly preventing it from being treated as a build target.
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||
"$<LINK_ONLY:${CMAKE_CURRENT_SOURCE_DIR}/lib/libdpp.so.10.1.4>" # Corrected 'libs' to 'lib'
|
||||
)
|
||||
|
||||
# Set C++ version
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES
|
||||
CXX_STANDARD 20
|
||||
CXX_STANDARD_REQUIRED ON
|
||||
)
|
||||
152
Makefile
Normal file
152
Makefile
Normal file
@ -0,0 +1,152 @@
|
||||
# Project configuration
|
||||
EXECUTABLE_NAME = poomer-discord-helloworld
|
||||
PLATFORM = $(shell uname)
|
||||
BUILD_TYPE ?= release# Default to release build if not specified
|
||||
|
||||
# Version configuration (can be overridden)
|
||||
DPP_VERSION ?= $(shell find ../DPP/build/library -name "libdpp.so.*.*.*" -type f | head -1 | sed 's/.*libdpp\.so\.//')
|
||||
DPP_VERSION := $(or $(DPP_VERSION),10.1.4)# Fallback version if auto-detection fails
|
||||
|
||||
# Common paths
|
||||
DPP_PATH = ../DPP
|
||||
OBJ_DIR = obj/$(PLATFORM)/$(BUILD_TYPE)
|
||||
BIN_DIR = bin/$(PLATFORM)/$(BUILD_TYPE)
|
||||
OUTPUT_FILE = $(BIN_DIR)/$(EXECUTABLE_NAME)
|
||||
|
||||
# Platform-specific configuration
|
||||
ifeq ($(PLATFORM), Darwin)
|
||||
# macOS configuration
|
||||
SDK_LIB_EXT = dylib
|
||||
DPP_LIB_NAME = libdpp.$(SDK_LIB_EXT)
|
||||
MACOS_SDK_PATH = /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk
|
||||
|
||||
# Compiler settings
|
||||
CC = clang
|
||||
CXX = clang++
|
||||
|
||||
# Architecture flags
|
||||
ARCH_FLAGS = -arch arm64 -mmacosx-version-min=11.0 -isysroot $(MACOS_SDK_PATH)
|
||||
|
||||
# Linking flags - Use multiple rpath entries to look in executable directory
|
||||
LINKER_FLAGS = $(ARCH_FLAGS) -framework Cocoa -framework IOKit -fvisibility=hidden -O5 \
|
||||
-rpath @executable_path \
|
||||
-rpath .
|
||||
else
|
||||
# Linux configuration
|
||||
SDK_LIB_EXT = so
|
||||
DPP_LIB_NAME = libdpp.$(SDK_LIB_EXT)
|
||||
|
||||
# Compiler settings
|
||||
CC = gcc
|
||||
CXX = g++
|
||||
|
||||
# Architecture flags
|
||||
ARCH_FLAGS = -m64 -D_FILE_OFFSET_BITS=64
|
||||
|
||||
# Linking flags
|
||||
LINKER_FLAGS = $(ARCH_FLAGS) -fvisibility=hidden -O3 -Wl,-rpath,'$$ORIGIN' -Wl,-rpath,'$$ORIGIN/lib'
|
||||
endif
|
||||
|
||||
# Common include and library paths
|
||||
INCLUDE_PATHS = -I$(DPP_PATH)/include
|
||||
DPP_BUILD_DIR = $(DPP_PATH)/build/library
|
||||
|
||||
# Platform-specific versioned library filename
|
||||
ifeq ($(PLATFORM), Darwin)
|
||||
DPP_VERSIONED_FILE = libdpp.$(DPP_VERSION).$(SDK_LIB_EXT)
|
||||
else
|
||||
DPP_VERSIONED_FILE = libdpp.$(SDK_LIB_EXT).$(DPP_VERSION)
|
||||
endif
|
||||
|
||||
# Library flags
|
||||
LIB_PATHS = -L$(DPP_BUILD_DIR)
|
||||
LIBRARIES = -ldpp
|
||||
|
||||
# Build type specific flags
|
||||
ifeq ($(BUILD_TYPE), debug)
|
||||
CPP_DEFINES = -D_DEBUG -DDL_USE_SHARED
|
||||
COMMON_FLAGS = $(ARCH_FLAGS) -fvisibility=hidden -g -O0 $(INCLUDE_PATHS)
|
||||
else
|
||||
CPP_DEFINES = -DNDEBUG=1 -DDL_USE_SHARED
|
||||
COMMON_FLAGS = $(ARCH_FLAGS) -fvisibility=hidden -O3 $(INCLUDE_PATHS)
|
||||
endif
|
||||
|
||||
# Language-specific flags
|
||||
C_FLAGS = $(COMMON_FLAGS) -std=c17
|
||||
CXX_FLAGS = $(COMMON_FLAGS) -std=c++17 -Wno-deprecated-declarations
|
||||
|
||||
# Objects
|
||||
OBJECTS = $(EXECUTABLE_NAME).o
|
||||
OBJECT_FILES = $(patsubst %,$(OBJ_DIR)/%,$(OBJECTS))
|
||||
|
||||
# Build rules
|
||||
$(OBJ_DIR)/$(EXECUTABLE_NAME).o: $(EXECUTABLE_NAME).cpp
|
||||
@mkdir -p $(@D)
|
||||
$(CXX) -c -o $@ $< $(CXX_FLAGS) $(CPP_DEFINES)
|
||||
|
||||
$(OUTPUT_FILE): $(OBJECT_FILES)
|
||||
@mkdir -p $(@D)
|
||||
$(CXX) -o $@ $(OBJECT_FILES) $(LINKER_FLAGS) $(LIB_PATHS) $(LIBRARIES)
|
||||
@echo "Copying libraries to $(BIN_DIR)..."
|
||||
ifeq ($(PLATFORM), Darwin)
|
||||
@# macOS: Handle versioned libraries (same as Linux)
|
||||
@if [ -f $(DPP_BUILD_DIR)/$(DPP_VERSIONED_FILE) ]; then \
|
||||
cp $(DPP_BUILD_DIR)/$(DPP_VERSIONED_FILE) $(BIN_DIR)/$(DPP_VERSIONED_FILE); \
|
||||
ln -sf $(DPP_VERSIONED_FILE) $(BIN_DIR)/$(DPP_LIB_NAME); \
|
||||
else \
|
||||
cp $(DPP_BUILD_DIR)/$(DPP_LIB_NAME) $(BIN_DIR)/$(DPP_LIB_NAME); \
|
||||
fi
|
||||
else
|
||||
@# Linux: Handle versioned libraries (follow standard convention)
|
||||
@if [ -f $(DPP_BUILD_DIR)/$(DPP_VERSIONED_FILE) ]; then \
|
||||
cp $(DPP_BUILD_DIR)/$(DPP_VERSIONED_FILE) $(BIN_DIR)/$(DPP_VERSIONED_FILE); \
|
||||
ln -sf $(DPP_VERSIONED_FILE) $(BIN_DIR)/$(DPP_LIB_NAME); \
|
||||
else \
|
||||
cp $(DPP_BUILD_DIR)/$(DPP_LIB_NAME) $(BIN_DIR)/$(DPP_LIB_NAME); \
|
||||
fi
|
||||
endif
|
||||
@echo "Build complete: $(OUTPUT_FILE)"
|
||||
|
||||
# Boilerplate for makefile
|
||||
.PHONY: clean cleanall all info
|
||||
|
||||
# Add default target
|
||||
all: $(OUTPUT_FILE)
|
||||
|
||||
info:
|
||||
@echo "Build Configuration:"
|
||||
@echo " Platform: $(PLATFORM)"
|
||||
@echo " Build Type: $(BUILD_TYPE)"
|
||||
@echo " DPP Version (detected): $(DPP_VERSION)"
|
||||
@echo " DPP Versioned File: $(DPP_VERSIONED_FILE)"
|
||||
@echo " SDK Library Extension: $(SDK_LIB_EXT)"
|
||||
@echo " Output File: $(OUTPUT_FILE)"
|
||||
|
||||
clean:
|
||||
rm -f $(OBJ_DIR)/$(EXECUTABLE_NAME).o
|
||||
rm -f $(OUTPUT_FILE)
|
||||
rm -f $(BIN_DIR)/$(DPP_LIB_NAME)
|
||||
rm -f $(BIN_DIR)/$(DPP_VERSIONED_FILE)
|
||||
rm -f $(BIN_DIR)/*.$(SDK_LIB_EXT)
|
||||
rmdir $(OBJ_DIR) 2>/dev/null || true
|
||||
rmdir $(BIN_DIR) 2>/dev/null || true
|
||||
|
||||
cleanall:
|
||||
rm -f obj/*/release/*.o
|
||||
rm -f obj/*/debug/*.o
|
||||
rm -f bin/*/release/$(EXECUTABLE_NAME)
|
||||
rm -f bin/*/debug/$(EXECUTABLE_NAME)
|
||||
rm -f bin/*/release/$(DPP_LIB_NAME)
|
||||
rm -f bin/*/debug/$(DPP_LIB_NAME)
|
||||
rm -f bin/*/release/$(DPP_VERSIONED_FILE)
|
||||
rm -f bin/*/debug/$(DPP_VERSIONED_FILE)
|
||||
rm -f bin/*/release/*.$(SDK_LIB_EXT)
|
||||
rm -f bin/*/debug/*.$(SDK_LIB_EXT)
|
||||
rmdir obj/*/release 2>/dev/null || true
|
||||
rmdir obj/*/debug 2>/dev/null || true
|
||||
rmdir bin/*/release 2>/dev/null || true
|
||||
rmdir bin/*/debug 2>/dev/null || true
|
||||
rmdir obj/* 2>/dev/null || true
|
||||
rmdir bin/* 2>/dev/null || true
|
||||
rmdir obj 2>/dev/null || true
|
||||
rmdir bin 2>/dev/null || true
|
||||
33
README.md
33
README.md
@ -1,31 +1,11 @@
|
||||
# poomer-discord-hello-world
|
||||
Displays an image in reverse on the discord server after dropping in on a discord channel
|
||||
These are very similar to the instructions from https://git.indoodle.com/jason/bellatui
|
||||
|
||||
Follow instructions to create a bot for your discord server at https://dpp.dev/creating-a-bot-application.html The link will also show you how to create a bot token as well. Create a token.txt file in your workdir folder. Copy the bot token and paste it into token.txt.
|
||||
Summary:
|
||||
- we keep our repo limited to our .cpp and Makefile and .vcxproj
|
||||
- we git clone thrid party repos and build using cli tools
|
||||
- we include the headers using "../DPP/" "../bella_engine_sdk/" etc. This relative path avoids having to install systemwide libs when possible and these third party libs can get reused by other poomer apps
|
||||
- we maintain a similar dir structure for all poomer apps as they are learning apps
|
||||
|
||||
## Usage
|
||||
./discord-bot
|
||||
|
||||
# Build
|
||||
```
|
||||
workdir/
|
||||
├── build_engine_sdk/
|
||||
├── poomer-discord-hello-world/
|
||||
└── lib
|
||||
└── dpp # contains include files of D++
|
||||
├── DPP/
|
||||
├── makefile
|
||||
├── README.md
|
||||
└── token.txt
|
||||
```
|
||||
|
||||
## Linux
|
||||
|
||||
### bella_engine_sdk
|
||||
```
|
||||
curl -O https://downloads.bellarender.com/bella_engine_sdk-24.6.0.tar.gz
|
||||
tar -xvf bella_engine_sdk-24.6.0.tar.gz
|
||||
```
|
||||
|
||||
```
|
||||
mkdir workdir
|
||||
@ -37,6 +17,7 @@ cmake --build ./build -j4
|
||||
cd ..
|
||||
git clone https://git.indoodle.com/oomer/poomer-discord-helloworld.git
|
||||
cd poomer-discord-helloworld
|
||||
git switch oomer/suggestions
|
||||
```
|
||||
For a prototype app we can just dump the stb headers right into the helloworld dir for simplicity
|
||||
```
|
||||
|
||||
228
discord-bot.cpp
228
discord-bot.cpp
@ -1,228 +0,0 @@
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
|
||||
#include <dpp/dpp.h>
|
||||
#include <iostream>
|
||||
#include <fstream> // Required for file operations
|
||||
#include <vector> // Required for std::vector
|
||||
#include <string>
|
||||
|
||||
#include "stb_image.h"
|
||||
#include "stb_image_write.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
void flip_image_horizontally(unsigned char* data, int width, int height, int channels);
|
||||
void flip_image_vertically(unsigned char* data, int width, int height, int channels);
|
||||
void process_attachment(dpp::cluster& bot, const dpp::message_create_t& event, const dpp::attachment& attachment);
|
||||
|
||||
int main() {
|
||||
|
||||
// --- Load the bot token from a file ---
|
||||
string token_file_path = "token.txt";
|
||||
|
||||
ifstream token_file(token_file_path);
|
||||
string bot_token;
|
||||
if (!token_file.is_open()) {
|
||||
// if not, try parent directory
|
||||
if (!token_file.is_open()) {
|
||||
token_file_path = "../token.txt";
|
||||
token_file.open(token_file_path);
|
||||
if (!token_file.is_open())
|
||||
{
|
||||
cerr << "ERROR: Could not open token.txt. Please create the file and add your bot token." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
getline(token_file, bot_token);
|
||||
token_file.close();
|
||||
|
||||
if (bot_token.empty()) {
|
||||
std::cerr << "ERROR: Token file is empty. Please add your bot token to token.txt." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
dpp::cluster bot(bot_token, dpp::i_default_intents | dpp::i_message_content);
|
||||
|
||||
bot.on_log(dpp::utility::cout_logger()); // Corrected: no 'true' argument
|
||||
|
||||
std::cout<<"in main"<<endl;
|
||||
// Create an instance of your ImageProcessor class
|
||||
//ImageProcessor image_processor(bot);
|
||||
|
||||
bot.on_slashcommand([&bot](const dpp::slashcommand_t& event) {
|
||||
std::cout << "Received slash cmd" << std::endl << std::flush; // Keep for testing
|
||||
bot.log(dpp::ll_info, "Received slash command: " + event.command.get_command_name());
|
||||
if (event.command.get_command_name() == "ping") {
|
||||
bot.log(dpp::ll_info, "Processing /ping command. Replying now!");
|
||||
event.reply("Pong!");
|
||||
} else {
|
||||
bot.log(dpp::ll_info, "Received unknown slash command: " + event.command.get_command_name());
|
||||
}
|
||||
});
|
||||
|
||||
bot.on_ready([&bot](const dpp::ready_t& event) {
|
||||
bot.log(dpp::ll_info, "Bot ready. Logged in as: " + bot.me.username);
|
||||
|
||||
if (dpp::run_once<struct register_bot_commands>()) {
|
||||
bot.log(dpp::ll_info, "Registering global /ping command...");
|
||||
bot.global_command_create(dpp::slashcommand("ping", "Ping pong!", bot.me.id));
|
||||
}
|
||||
});
|
||||
|
||||
bot.on_message_create([&bot](const dpp::message_create_t& event) {
|
||||
// Ignore messages from the bot itself to prevent infinite loops
|
||||
bot.log(dpp::ll_info, "author id: " + to_string(event.msg.author.id));
|
||||
bot.log(dpp::ll_info, "bot id: " + to_string(bot.me.id));
|
||||
if (event.msg.author.id == bot.me.id) {
|
||||
bot.log(dpp::ll_info, "Ignoring message, author and bot id match");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the message has any attachments
|
||||
if (!event.msg.attachments.empty()) { //
|
||||
// Log that an attachment was found
|
||||
bot.log(dpp::ll_info, "Message from " + event.msg.author.username + " contains attachments!");
|
||||
|
||||
// You can iterate through the attachments if you need details about each one
|
||||
for (const auto& attachment : event.msg.attachments) { //
|
||||
bot.log(dpp::ll_info, " Attachment ID: " + std::to_string(attachment.id) +
|
||||
", Filename: " + attachment.filename +
|
||||
", Size: " + std::to_string(attachment.size) + " bytes");
|
||||
// You can also get the URL of the attachment: attachment.url
|
||||
// And a proxied URL: attachment.proxy_url
|
||||
std::string filename = attachment.filename;
|
||||
|
||||
|
||||
if (filename.substr(strlen(filename.c_str())-3,3) == "jpg")
|
||||
{
|
||||
bot.log(dpp::ll_info, "jpg detected");
|
||||
|
||||
std::string local_filename = "temp_" + attachment.filename;
|
||||
|
||||
process_attachment(bot,event,attachment);
|
||||
bot.log(dpp::ll_info, "image flipped horizontally");
|
||||
// Download the attachment first
|
||||
//download_file(bot, event, attachment.url, local_filename); //
|
||||
|
||||
// Note: The download is asynchronous. You would typically do
|
||||
// further processing in the http_request_completion_t handler.
|
||||
// For a simple example, you might call load_image from there.
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Example: Reply to the user saying you detected an attachment
|
||||
// event.reply("Thanks for the attachment!");
|
||||
} else {
|
||||
// Log if no attachments were found
|
||||
bot.log(dpp::ll_info, "Message from " + event.msg.author.username + " has no attachments.");
|
||||
}
|
||||
|
||||
// You can also add logic for processing other types of messages or commands here
|
||||
});
|
||||
|
||||
std::cerr << "--- Direct stderr test: Bot is about to start listening ---" << std::endl;
|
||||
|
||||
bot.start(dpp::st_wait);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void process_attachment(dpp::cluster& bot, const dpp::message_create_t& event, const dpp::attachment& attachment) {
|
||||
std::string local_filename = "temp_" + std::to_string(attachment.id) + "_" + attachment.filename;
|
||||
|
||||
bot.request(attachment.url, dpp::http_method::m_get,
|
||||
[ &bot, event, local_filename, attachment](const dpp::http_request_completion_t& completion) {
|
||||
if (completion.status < 400) {
|
||||
std::ofstream file(local_filename, std::ios::binary);
|
||||
if (file.is_open()) {
|
||||
file.write(completion.body.c_str(), completion.body.length());
|
||||
file.close();
|
||||
|
||||
int width, height, channels;
|
||||
//unsigned char* image_data = stbi_load_from_memory(local_filename.c_str(), &width, &height, &channels, 0);
|
||||
unsigned char* image_data = stbi_load_from_memory(
|
||||
reinterpret_cast<const stbi_uc*>(completion.body.data()),
|
||||
completion.body.length(),
|
||||
&width, &height, &channels, 0
|
||||
);
|
||||
if (image_data) {
|
||||
// Flip the image horizontally (you can choose which flip to apply)
|
||||
bot.log(dpp::ll_info,"channels: " + std::to_string(channels));
|
||||
flip_image_horizontally(image_data, width, height, channels);
|
||||
|
||||
// --- Save the flipped image to a new temporary file ---
|
||||
std::string flipped_filename = "flipped_" + local_filename;
|
||||
stbi_write_jpg(flipped_filename.c_str(), width, height, channels, image_data, 100); // Quality 100
|
||||
|
||||
// --- NEW CODE STARTS HERE ---
|
||||
dpp::message msg;
|
||||
|
||||
// Add the file to the message
|
||||
msg.add_file(flipped_filename, dpp::utility::read_file(flipped_filename));
|
||||
|
||||
// Create an embed and reference the attached file
|
||||
dpp::embed embed;
|
||||
embed.set_title("Image Info");
|
||||
embed.set_description("Dimensions: " + std::to_string(width) + "x" + std::to_string(height));
|
||||
embed.set_image("attachment://" + flipped_filename); // Reference the file here
|
||||
|
||||
// Add the embed to the message
|
||||
msg.add_embed(embed);
|
||||
msg.set_channel_id(1398043078559797310);
|
||||
bot.message_create(msg);
|
||||
|
||||
msg.set_content("Here's your horizontally flipped image");
|
||||
event.reply(msg);
|
||||
// --- NEW CODE ENDS HERE ---
|
||||
|
||||
stbi_image_free(image_data);
|
||||
std::remove(local_filename.c_str());
|
||||
std::remove(flipped_filename.c_str()); // Clean up the flipped file
|
||||
} else {
|
||||
std::cerr << "Error: Failed to load image with stb from " << local_filename << std::endl;
|
||||
}
|
||||
std::remove(local_filename.c_str());
|
||||
} else {
|
||||
std::cerr << "Failed to open local file for writing: " << local_filename << std::endl;
|
||||
}
|
||||
} else {
|
||||
std::cerr << "Failed to download image from " << attachment.url << ". HTTP status code: " << completion.status << std::endl;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void flip_image_horizontally(unsigned char* data, int width, int height, int channels) {
|
||||
|
||||
for (int y = 0; y < height; ++y) {
|
||||
// Get pointers to the start of the current row
|
||||
unsigned char* row_start = data + y * width * channels;
|
||||
|
||||
// Loop through half the row, swapping pixels from left and right
|
||||
for (int x = 0; x < width / 2; ++x) {
|
||||
// Calculate the pointers to the left and right pixels
|
||||
unsigned char* left_pixel = row_start + x * channels;
|
||||
unsigned char* right_pixel = row_start + (width - 1 - x) * channels;
|
||||
|
||||
// Swap each channel of the pixels
|
||||
for (int c = 0; c < channels; ++c) {
|
||||
std::swap(left_pixel[c], right_pixel[c]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void flip_image_vertically(unsigned char* data, int width, int height, int channels) {
|
||||
// ... (your vertical flip implementation from before)
|
||||
int row_stride = width * channels;
|
||||
unsigned char* temp_row = new unsigned char [row_stride];
|
||||
for (int y = 0; y < height / 2; ++y) {
|
||||
unsigned char* top_row = data + y * row_stride;
|
||||
unsigned char* bottom_row = data + (height - 1 - y) * row_stride;
|
||||
std::memcpy(temp_row, top_row, row_stride);
|
||||
std::memcpy(top_row, bottom_row, row_stride);
|
||||
std::memcpy(bottom_row, temp_row, row_stride);
|
||||
}
|
||||
delete[] temp_row;
|
||||
}
|
||||
94
makefile
94
makefile
@ -1,94 +0,0 @@
|
||||
|
||||
# Project configuration
|
||||
EXECUTABLE_NAME = discord-bot
|
||||
PLATFORM = $(shell uname)
|
||||
BUILD_TYPE ?= release# Default to release build if not specified
|
||||
|
||||
STB_PATH = $(HOME)/workdir/stb
|
||||
LINUX_LIB_EXT = so
|
||||
|
||||
# Version configuration (can be overridden)
|
||||
DPP_VERSION ?= $(shell find ../DPP/build/library -name "libdpp.so.*.*.*" -type f | head -1 | sed 's/.*libdpp\.so\.//')
|
||||
DPP_PATH = $(HOME)/workdir/DPP
|
||||
DPP_BUILD_DIR = $(DPP_PATH)/build/library
|
||||
LIB_PATHS = $(DPP_BUILD_DIR)
|
||||
INC_DIRS = -Iinclude -I$(DPP_PATH)/include/ -I$(STB_PATH)
|
||||
#endif
|
||||
|
||||
DPP_VERSION := $(or $(DPP_VERSION),10.1.4)# Fallback version if auto-detection fails
|
||||
DPP_LINUX_LIB_VERSION_FILE = libdpp.$(LINUX_LIB_EXT).$(DPP_VERSION)
|
||||
DPP_LIB_NAME = libdpp.$(LINUX_LIB_EXT)
|
||||
|
||||
# Common paths
|
||||
OBJ_DIR = obj/$(PLATFORM)/$(BUILD_TYPE)
|
||||
BIN_DIR = bin/$(PLATFORM)/$(BUILD_TYPE)
|
||||
OUTPUT_FILE = $(BIN_DIR)/$(EXECUTABLE_NAME)
|
||||
|
||||
|
||||
|
||||
# Build type specific flags
|
||||
ifeq ($(BUILD_TYPE), debug)
|
||||
CPP_DEFINES = -D_DEBUG -DDL_USE_SHARED
|
||||
COMMON_FLAGS = $(ARCH_FLAGS) -fvisibility=hidden -g -O0 $(INCLUDE_PATHS)
|
||||
else
|
||||
CPP_DEFINES = -DNDEBUG=1 -DDL_USE_SHARED
|
||||
COMMON_FLAGS = $(ARCH_FLAGS) -fvisibility=hidden -O3 $(INCLUDE_PATHS)
|
||||
endif
|
||||
|
||||
# Language-specific flags
|
||||
C_FLAGS = $(COMMON_FLAGS) -std=c17
|
||||
CXX_FLAGS = $(COMMON_FLAGS) -std=c++17 -Wall -g $(INC_DIRS)
|
||||
|
||||
# Linker directive flags (L for library search path, l for library)
|
||||
# Need to link against the D++ library and pthread (common for C++ applications with threading)
|
||||
LDFLAGS = -L$(LIB_PATHS) -ldpp -lpthread -Wl,-rpath='$$ORIGIN' # search for lib in the same place as the executable file
|
||||
|
||||
# List of object files for your executable
|
||||
# We've changed this back to use discord-bot.o as the source of the executable
|
||||
OBJECTS = $(OBJ_DIR)/discord-bot.o
|
||||
|
||||
# --- Main Target ---
|
||||
# 'all' is the default target that builds your executable
|
||||
all: $(OUTPUT_FILE)
|
||||
@echo "DPP_PATH: "$(DPP_PATH)
|
||||
@echo "Build complete."
|
||||
|
||||
# Rule to link the executable:
|
||||
# It depends on the object files and uses CXX to link them with specified libraries.
|
||||
$(OUTPUT_FILE): $(OBJECTS)
|
||||
@echo "Linking $(OUTPUT_FILE)..."
|
||||
@echo "LDFLAGS: $(LDFLAGS)"
|
||||
@mkdir -p $(@D) # Ensure the output binary directory exists (e.g., bin/Linux/release/)
|
||||
$(CXX) -o $@ $(OBJECTS) $(LDFLAGS)
|
||||
@if test -f token.txt; then \
|
||||
echo "Copying token.txt to $(@D)"; \
|
||||
cp token.txt $(@D); \
|
||||
if test -f $(DPP_BUILD_DIR)/$(DPP_LINUX_LIB_VERSION_FILE); then \
|
||||
cp $(DPP_BUILD_DIR)/$(DPP_LINUX_LIB_VERSION_FILE) $(BIN_DIR)/$(DPP_LINUX_LIB_VERSION_FILE); \
|
||||
ln -sf $(DPP_LINUX_LDPP_LINUX_LIB_VERSION_FILEIB_FILE) $(BIN_DIR)/$(DPP_LIB_NAME); \
|
||||
else \
|
||||
cp $(DPP_BUILD_DIR)/$(DPP_LIB_NAME) $(BIN_DIR)/$(DPP_LIB_NAME); \
|
||||
fi \
|
||||
else \
|
||||
echo "Error: token.txt not found! Please create it in the project root. Copy the token when you create your discord bot and paste it in token.txt"; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
|
||||
|
||||
# Rule to compile the object file:
|
||||
# This takes your .cpp source file and compiles it into an object file (.o).
|
||||
$(OBJ_DIR)/$(EXECUTABLE_NAME).o: $(EXECUTABLE_NAME).cpp
|
||||
@echo "Compiling $< to $@"
|
||||
@mkdir -p $(@D) # Ensure the object directory exists (e.g., obj/Linux/release/)
|
||||
$(CXX) -c -o $@ $< $(CXX_FLAGS) $(CPP_DEFINES)
|
||||
|
||||
# --- Clean Target ---
|
||||
# Removes all generated build files and directories
|
||||
clean:
|
||||
@echo "Cleaning build directory..."
|
||||
$(RM) -r $(BIN_DIR)
|
||||
$(RM) -r $(OBJ_DIR)
|
||||
|
||||
# .PHONY specifies targets that are not actual files to prevent conflicts with file names
|
||||
.PHONY: all clean
|
||||
251
poomer-discord-helloworld.cpp
Normal file
251
poomer-discord-helloworld.cpp
Normal file
@ -0,0 +1,251 @@
|
||||
// Discord bot library - provides all Discord API functionality
|
||||
#include "../DPP/include/dpp/dpp.h"
|
||||
#include <iostream>
|
||||
#include <fstream> // Required for file operations
|
||||
#include <vector> // Required for std::vector
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
// STB Image library - single header for loading images (JPEG, PNG, etc.)
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb_image.h"
|
||||
|
||||
// STB Image Write library - single header for saving images
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#include "stb_image_write.h"
|
||||
|
||||
// ImageProcessor class declaration
|
||||
class ImageProcessor {
|
||||
private:
|
||||
dpp::cluster& m_bot;
|
||||
|
||||
public:
|
||||
ImageProcessor(dpp::cluster& bot);
|
||||
void flip_image_horizontally(unsigned char* data, int width, int height, int channels);
|
||||
void flip_image_vertically(unsigned char* data, int width, int height, int channels);
|
||||
void process_attachment(const dpp::message_create_t& event, const dpp::attachment& attachment);
|
||||
};
|
||||
|
||||
ImageProcessor::ImageProcessor(dpp::cluster& bot) : m_bot(bot) {
|
||||
// Constructor initializes the member variable
|
||||
}
|
||||
|
||||
void ImageProcessor::flip_image_horizontally(unsigned char* data, int width, int height, int channels) {
|
||||
// ... (your horizontal flip implementation from before)
|
||||
/*for (int y = 0; y < height; ++y) {
|
||||
unsigned char *left = data + y * width * channels;
|
||||
unsigned char *right = left + (width - 1) * channels;
|
||||
for (int x = 0; x < width / 2; ++x) {
|
||||
for (int c = 0; c < channels; ++c) {
|
||||
std::swap(left[(x * channels) + c], right[(0 * channels) + c]);
|
||||
}
|
||||
left += channels;
|
||||
right -= channels;
|
||||
}
|
||||
}*/
|
||||
for (int y = 0; y < height; ++y) {
|
||||
// Get pointers to the start of the current row
|
||||
unsigned char* row_start = data + y * width * channels;
|
||||
|
||||
// Loop through half the row, swapping pixels from left and right
|
||||
for (int x = 0; x < width / 2; ++x) {
|
||||
// Calculate the pointers to the left and right pixels
|
||||
unsigned char* left_pixel = row_start + x * channels;
|
||||
unsigned char* right_pixel = row_start + (width - 1 - x) * channels;
|
||||
|
||||
// Swap each channel of the pixels
|
||||
for (int c = 0; c < channels; ++c) {
|
||||
std::swap(left_pixel[c], right_pixel[c]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ImageProcessor::flip_image_vertically(unsigned char* data, int width, int height, int channels) {
|
||||
// ... (your vertical flip implementation from before)
|
||||
int row_stride = width * channels;
|
||||
unsigned char* temp_row = new unsigned char [row_stride];
|
||||
for (int y = 0; y < height / 2; ++y) {
|
||||
unsigned char* top_row = data + y * row_stride;
|
||||
unsigned char* bottom_row = data + (height - 1 - y) * row_stride;
|
||||
std::memcpy(temp_row, top_row, row_stride);
|
||||
std::memcpy(top_row, bottom_row, row_stride);
|
||||
std::memcpy(bottom_row, temp_row, row_stride);
|
||||
}
|
||||
delete[] temp_row;
|
||||
}
|
||||
|
||||
void ImageProcessor::process_attachment(const dpp::message_create_t& event, const dpp::attachment& attachment) {
|
||||
std::string local_filename = "temp_" + std::to_string(attachment.id) + "_" + attachment.filename;
|
||||
|
||||
m_bot.request(attachment.url, dpp::http_method::m_get,
|
||||
[this, event, local_filename, attachment](const dpp::http_request_completion_t& completion) {
|
||||
if (completion.status < 400) {
|
||||
std::ofstream file(local_filename, std::ios::binary);
|
||||
if (file.is_open()) {
|
||||
file.write(completion.body.c_str(), completion.body.length());
|
||||
file.close();
|
||||
|
||||
int width, height, channels;
|
||||
//unsigned char* image_data = stbi_load_from_memory(local_filename.c_str(), &width, &height, &channels, 0);
|
||||
unsigned char* image_data = stbi_load_from_memory(
|
||||
reinterpret_cast<const stbi_uc*>(completion.body.data()),
|
||||
completion.body.length(),
|
||||
&width, &height, &channels, 0
|
||||
);
|
||||
if (image_data) {
|
||||
// Flip the image horizontally (you can choose which flip to apply)
|
||||
m_bot.log(dpp::ll_info,"channels: " + std::to_string(channels));
|
||||
flip_image_horizontally(image_data, width, height, channels);
|
||||
|
||||
// --- Save the flipped image to a new temporary file ---
|
||||
std::string flipped_filename = "flipped_" + local_filename;
|
||||
stbi_write_jpg(flipped_filename.c_str(), width, height, channels, image_data, 100); // Quality 100
|
||||
|
||||
// --- NEW CODE STARTS HERE ---
|
||||
dpp::message msg;
|
||||
|
||||
// Add the file to the message
|
||||
msg.add_file(flipped_filename, dpp::utility::read_file(flipped_filename));
|
||||
|
||||
// Create an embed and reference the attached file
|
||||
dpp::embed embed;
|
||||
embed.set_title("Image Info");
|
||||
embed.set_description("Dimensions: " + std::to_string(width) + "x" + std::to_string(height));
|
||||
embed.set_image("attachment://" + flipped_filename); // Reference the file here
|
||||
|
||||
// Add the embed to the message
|
||||
msg.add_embed(embed);
|
||||
msg.set_channel_id(1398043078559797310);
|
||||
m_bot.message_create(msg);
|
||||
|
||||
msg.set_content("Here's your horizontally flipped image");
|
||||
event.reply(msg);
|
||||
// --- NEW CODE ENDS HERE ---
|
||||
|
||||
stbi_image_free(image_data);
|
||||
std::remove(local_filename.c_str());
|
||||
std::remove(flipped_filename.c_str()); // Clean up the flipped file
|
||||
} else {
|
||||
std::cerr << "Error: Failed to load image with stb from " << local_filename << std::endl;
|
||||
}
|
||||
std::remove(local_filename.c_str());
|
||||
} else {
|
||||
std::cerr << "Failed to open local file for writing: " << local_filename << std::endl;
|
||||
}
|
||||
} else {
|
||||
std::cerr << "Failed to download image from " << attachment.url << ". HTTP status code: " << completion.status << std::endl;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
// --- Load the bot token from a file ---
|
||||
string token_file_path = "token.txt";
|
||||
|
||||
ifstream token_file(token_file_path);
|
||||
string bot_token;
|
||||
if (!token_file.is_open()) {
|
||||
// if not, try parent directory
|
||||
if (!token_file.is_open()) {
|
||||
token_file_path = "../token.txt";
|
||||
token_file.open(token_file_path);
|
||||
if (!token_file.is_open())
|
||||
{
|
||||
cerr << "ERROR: Could not open token.txt. Please create the file and add your bot token." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
getline(token_file, bot_token);
|
||||
token_file.close();
|
||||
|
||||
if (bot_token.empty()) {
|
||||
std::cerr << "ERROR: Token file is empty. Please add your bot token to token.txt." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
dpp::cluster bot(bot_token, dpp::i_default_intents | dpp::i_message_content);
|
||||
|
||||
bot.on_log(dpp::utility::cout_logger()); // Corrected: no 'true' argument
|
||||
|
||||
std::cout<<"in main"<<endl;
|
||||
// Create an instance of your ImageProcessor class
|
||||
ImageProcessor image_processor(bot);
|
||||
|
||||
bot.on_slashcommand([&bot](const dpp::slashcommand_t& event) {
|
||||
std::cout << "Received slash cmd" << std::endl << std::flush; // Keep for testing
|
||||
bot.log(dpp::ll_info, "Received slash command: " + event.command.get_command_name());
|
||||
if (event.command.get_command_name() == "ping") {
|
||||
bot.log(dpp::ll_info, "Processing /ping command. Replying now!");
|
||||
event.reply("Pong!");
|
||||
} else {
|
||||
bot.log(dpp::ll_info, "Received unknown slash command: " + event.command.get_command_name());
|
||||
}
|
||||
});
|
||||
|
||||
bot.on_ready([&bot](const dpp::ready_t& event) {
|
||||
bot.log(dpp::ll_info, "Bot ready. Logged in as: " + bot.me.username);
|
||||
|
||||
if (dpp::run_once<struct register_bot_commands>()) {
|
||||
bot.log(dpp::ll_info, "Registering global /ping command...");
|
||||
bot.global_command_create(dpp::slashcommand("ping", "Ping pong!", bot.me.id));
|
||||
}
|
||||
});
|
||||
|
||||
bot.on_message_create([&image_processor, &bot](const dpp::message_create_t& event) {
|
||||
// Ignore messages from the bot itself to prevent infinite loops
|
||||
if (event.msg.author.id == bot.me.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the message has any attachments
|
||||
if (!event.msg.attachments.empty()) { //
|
||||
// Log that an attachment was found
|
||||
bot.log(dpp::ll_info, "Message from " + event.msg.author.username + " contains attachments!");
|
||||
|
||||
// You can iterate through the attachments if you need details about each one
|
||||
for (const auto& attachment : event.msg.attachments) { //
|
||||
bot.log(dpp::ll_info, " Attachment ID: " + std::to_string(attachment.id) +
|
||||
", Filename: " + attachment.filename +
|
||||
", Size: " + std::to_string(attachment.size) + " bytes");
|
||||
// You can also get the URL of the attachment: attachment.url
|
||||
// And a proxied URL: attachment.proxy_url
|
||||
std::string filename = attachment.filename;
|
||||
|
||||
|
||||
if (filename.substr(strlen(filename.c_str())-3,3) == "jpg")
|
||||
{
|
||||
bot.log(dpp::ll_info, "jpg detected");
|
||||
|
||||
std::string local_filename = "temp_" + attachment.filename;
|
||||
|
||||
image_processor.process_attachment(event,attachment);
|
||||
bot.log(dpp::ll_info, "image flipped horizontally");
|
||||
// Download the attachment first
|
||||
//download_file(bot, event, attachment.url, local_filename); //
|
||||
|
||||
// Note: The download is asynchronous. You would typically do
|
||||
// further processing in the http_request_completion_t handler.
|
||||
// For a simple example, you might call load_image from there.
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Example: Reply to the user saying you detected an attachment
|
||||
// event.reply("Thanks for the attachment!");
|
||||
} else {
|
||||
// Log if no attachments were found
|
||||
bot.log(dpp::ll_info, "Message from " + event.msg.author.username + " has no attachments.");
|
||||
}
|
||||
|
||||
// You can also add logic for processing other types of messages or commands here
|
||||
});
|
||||
|
||||
std::cerr << "--- Direct stderr test: Bot is about to start listening ---" << std::endl;
|
||||
|
||||
bot.start(dpp::st_wait);
|
||||
return 0;
|
||||
}
|
||||
7988
src/stb_image.h
Normal file
7988
src/stb_image.h
Normal file
File diff suppressed because it is too large
Load Diff
1724
src/stb_image_write.h
Normal file
1724
src/stb_image_write.h
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user