join, play 구현

This commit is contained in:
2023-12-12 22:20:01 +09:00
parent 8b0d0bbff7
commit b2f40f21cf
26 changed files with 526 additions and 108 deletions

7
.gitignore vendored Normal file
View File

@@ -0,0 +1,7 @@
build/
out/
.vs/
.vscode/
.idea/
tmp/
config.json

View File

30
.vscode/launch.json vendored
View File

@@ -1,7 +1,29 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": []
"configurations": [
{
"name": "Debug",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/BumbleCee",
"stopAtEntry": false,
"cwd": "${fileDirname}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"description": "Set Disassembly Flavor to Intel",
"text": "-gdb-set disassembly-flavor intel",
"ignoreFailures": true
}
],
"preLaunchTask": "${defaultBuildTask}"
}
]
}

85
.vscode/settings.json vendored
View File

@@ -1,19 +1,56 @@
{
"files.associations": {
"iostream": "cpp",
"any": "cpp",
"chrono": "cpp",
"codecvt": "cpp",
"compare": "cpp",
"condition_variable": "cpp",
"deque": "cpp",
"forward_list": "cpp",
"list": "cpp",
"string": "cpp",
"unordered_map": "cpp",
"vector": "cpp",
"exception": "cpp",
"functional": "cpp",
"iterator": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"optional": "cpp",
"string_view": "cpp",
"random": "cpp",
"*.tcc": "cpp",
"fstream": "cpp",
"future": "cpp",
"initializer_list": "cpp",
"istream": "cpp",
"mutex": "cpp",
"new": "cpp",
"ostream": "cpp",
"ranges": "cpp",
"semaphore": "cpp",
"shared_mutex": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"stop_token": "cpp",
"streambuf": "cpp",
"system_error": "cpp",
"thread": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"typeinfo": "cpp",
"valarray": "cpp",
"variant": "cpp",
"array": "cpp",
"atomic": "cpp",
"bit": "cpp",
"*.tcc": "cpp",
"bitset": "cpp",
"cctype": "cpp",
"chrono": "cpp",
"charconv": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"compare": "cpp",
"complex": "cpp",
"concepts": "cpp",
"condition_variable": "cpp",
"coroutine": "cpp",
"csignal": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
@@ -24,48 +61,14 @@
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
"list": "cpp",
"map": "cpp",
"set": "cpp",
"string": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp",
"vector": "cpp",
"exception": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"iterator": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"random": "cpp",
"ratio": "cpp",
"regex": "cpp",
"source_location": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"fstream": "cpp",
"future": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"istream": "cpp",
"limits": "cpp",
"mutex": "cpp",
"new": "cpp",
"numbers": "cpp",
"ostream": "cpp",
"semaphore": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"stop_token": "cpp",
"streambuf": "cpp",
"thread": "cpp",
"cinttypes": "cpp",
"typeinfo": "cpp"
"numbers": "cpp"
}
}

54
.vscode/tasks.json vendored
View File

@@ -1,31 +1,35 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "cppbuild",
"label": "C/C++: g++ build active file",
"command": "/usr/bin/g++",
"args": [
"-fdiagnostics-color=always",
"-g",
"${file}",
"-o",
"${fileDirname}/${fileBasenameNoExtension}",
"-I",
"${fileDirname}/include",
"-ldpp"
],
"options": {
"cwd": "${fileDirname}"
{
"type": "cppbuild",
"label": "make",
"command": "make",
"args": [],
"options": {
"cwd": "${fileDirname}/../build"
},
"group": {
"kind": "build",
"isDefault": true
},
"dependsOn": ["cmake"]
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
{
"type": "shell",
"label": "cmake",
"command": "cmake",
"args": [
".."
],
"options": {
"cwd": "${fileDirname}/../build"
},
"group": {
"kind": "build",
"isDefault": false
}
},
"detail": "compiler: /usr/bin/g++"
}
]
}
}

76
CMakeLists.txt Normal file
View File

@@ -0,0 +1,76 @@
cmake_minimum_required (VERSION 3.6)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
set(BOT_NAME "BumbleCee")
project(${BOT_NAME})
aux_source_directory("src" coresrc)
add_executable(${BOT_NAME} ${coresrc})
string(ASCII 27 Esc)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set_target_properties(${BOT_NAME} PROPERTIES
CXX_STANDARD 17
CXX_STANDARD_REQUIRED ON
)
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
find_package(Threads REQUIRED)
find_package(DPP)
if(APPLE)
if(CMAKE_APPLE_SILICON_PROCESSOR)
set(OPENSSL_ROOT_DIR "/opt/homebrew/opt/openssl")
else()
set(OPENSSL_ROOT_DIR "/usr/local/opt/openssl")
endif()
find_package(OpenSSL REQUIRED)
else()
find_package(OpenSSL REQUIRED)
endif()
target_include_directories(${BOT_NAME} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include
${OPENSSL_INCLUDE_DIR}
/usr/local/include/opus
)
target_link_libraries(${BOT_NAME}
dl
oggz
opus
opusfile
ogg
${CMAKE_THREAD_LIBS_INIT}
${OPENSSL_CRYPTO_LIBRARY}
${OPENSSL_SSL_LIBRARY}
)
if (DPP_FOUND)
target_link_libraries(${BOT_NAME} ${DPP_LIBRARIES})
target_include_directories(${BOT_NAME} PUBLIC ${DPP_INCLUDE_DIR})
else()
message(WARNING "Could not find DPP install. Building from source instead.")
option(DPP_BUILD_TEST "" OFF)
include(FetchContent)
FetchContent_Declare(
libdpp
GIT_REPOSITORY https://github.com/brainboxdotcc/DPP.git
GIT_TAG master)
FetchContent_GetProperties(libdpp)
if(NOT libdpp_POPULATED)
FetchContent_Populate(libdpp)
target_include_directories(${BOT_NAME} PUBLIC
${libdpp_SOURCE_DIR}/include
)
add_subdirectory(
${libdpp_SOURCE_DIR}
${libdpp_BINARY_DIR}
EXCLUDE_FROM_ALL)
endif()
target_link_libraries(${BOT_NAME} dpp)
endif()

BIN
audioplayback.ogg Normal file

Binary file not shown.

7
cmake/FindDPP.cmake Normal file
View File

@@ -0,0 +1,7 @@
find_path(DPP_INCLUDE_DIR NAMES dpp/dpp.h HINTS ${DPP_ROOT_DIR})
find_library(DPP_LIBRARIES NAMES dpp "libdpp.a" HINTS ${DPP_ROOT_DIR})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(DPP DEFAULT_MSG DPP_LIBRARIES DPP_INCLUDE_DIR)

View File

@@ -1,6 +0,0 @@
#include <Bot.hpp>
#include <iostream>
void IBot::test() {
std::cout << "작동함";
}

View File

@@ -1,9 +1,19 @@
#pragma once
#include "CommandType.hpp"
#include <dpp/dpp.h>
#include <memory>
class IBot{
class IBot {
private:
public:
void test();
IBot(std::string Token);
void AddCommand(ICommand &Command);
void Start();
std::shared_ptr<dpp::cluster> bot;
protected:
virtual void OnReady(const dpp::ready_t& event);
virtual void OnCommand(const dpp::slashcommand_t& event);
std::vector<ICommand*> CommandsArray;
};

View File

@@ -1,2 +0,0 @@
#include <BumbleCee.hpp>
#include <iostream>

View File

@@ -1,15 +0,0 @@
#pragma once
#include <Bot.hpp>
class BumbleCee : public IBot {
public:
static BumbleCee* getInstance() {
static BumbleCee instance;
return &instance;
}
protected:
private:
BumbleCee() {}
BumbleCee(const BumbleCee& ref) {}
~BumbleCee() {}
};

20
include/BumbleCeepp.hpp Normal file
View File

@@ -0,0 +1,20 @@
#pragma once
#include "Bot.hpp"
#include <string>
#include <list>
class BumbleCeepp : public IBot {
public:
static BumbleCeepp* GetInstance(std::string Token) {
static BumbleCeepp Instance(Token);
return &Instance;
}
void enqueue(std::string);
std::string dequeue();
protected:
std::list<std::string> MusicQueue;
private:
BumbleCeepp(std::string Token);
void OnCommand(const dpp::slashcommand_t& Event);
};

12
include/CommandType.hpp Normal file
View File

@@ -0,0 +1,12 @@
#pragma once
#include <dpp/dpp.h>
#include <vector>
#include <list>
class ICommand {
public:
virtual void operator() (const dpp::slashcommand_t& Event) = 0;
virtual void operator() (std::list<std::string>& MusicQueue, const dpp::slashcommand_t& Event) = 0;
std::vector<dpp::slashcommand> CommandObjectVector;
};

4
include/Commands.hpp Normal file
View File

@@ -0,0 +1,4 @@
#pragma once
#include "Commands/Play.hpp"
#include "Commands/Queue.hpp"
#include "Commands/Join.hpp"

10
include/Commands/Join.hpp Normal file
View File

@@ -0,0 +1,10 @@
#pragma once
#include "../CommandType.hpp"
class Join : public ICommand {
public:
Join(dpp::snowflake Id);
void operator()(const dpp::slashcommand_t& Event) {}
void operator()(std::list<std::string>& MusicQueue, const dpp::slashcommand_t& Event);
};

10
include/Commands/Play.hpp Normal file
View File

@@ -0,0 +1,10 @@
#pragma once
#include "../CommandType.hpp"
class Play : public ICommand {
public:
Play(dpp::snowflake Id);
void operator()(const dpp::slashcommand_t& Event) {}
void operator()(std::list<std::string>& MusicQueue, const dpp::slashcommand_t& Event);
};

View File

@@ -0,0 +1,10 @@
#pragma once
#include "../CommandType.hpp"
class Queue : public ICommand {
public:
Queue(dpp::snowflake Id);
void operator()(const dpp::slashcommand_t& Event) {}
void operator()(std::list<std::string>& MusicQueue, const dpp::slashcommand_t& Event);
};

BIN
main

Binary file not shown.

View File

@@ -1,13 +0,0 @@
#include "BumbleCee.hpp"
#include <iostream>
std::string Token = "NzE1OTE2NDg2MTIzOTc4ODEy.GtT2ek.5ckzjEbg73QDS_FEZY_BS-UVpf-ZSEpR98pn80";
int main() {
BumbleCee* my_bot = BumbleCee::getInstance();
IBot bot;
bot.test();
return 0;
}

40
src/Bot.cpp Normal file
View File

@@ -0,0 +1,40 @@
#include "Bot.hpp"
IBot::IBot(std::string Token) {
bot = std::make_shared<dpp::cluster>(Token);
bot->on_log(dpp::utility::cout_logger());
bot->on_slashcommand([this](const dpp::slashcommand_t& Event) {OnCommand(Event);});
bot->on_ready([this](const dpp::ready_t& Event) {OnReady(Event);});
}
void IBot::AddCommand(ICommand &Command) {
CommandsArray.push_back(&Command);
}
void IBot::Start() {
bot->start(dpp::st_wait);
}
void IBot::OnReady(const dpp::ready_t& Event) {
if (!dpp::run_once<struct register_bot_commands>())
return;
bot->global_bulk_command_delete();
for (auto command : CommandsArray) {
for (auto Alias : command->CommandObjectVector) {
bot->global_command_create(Alias);
}
}
}
void IBot::OnCommand(const dpp::slashcommand_t& Event) {
for (auto Command : CommandsArray) {
for (auto Alias : Command->CommandObjectVector) {
if (Event.command.get_command_name() == Alias.name) {
(*Command)(Event);
}
}
}
}

15
src/BumbleCeepp.cpp Normal file
View File

@@ -0,0 +1,15 @@
#include "BumbleCeepp.hpp"
#include <string>
BumbleCeepp::BumbleCeepp(std::string Token) : IBot(Token) {
}
void BumbleCeepp::OnCommand(const dpp::slashcommand_t& Event) {
for (auto Command : CommandsArray) {
for (auto Alias : Command->CommandObjectVector) {
if (Event.command.get_command_name() == Alias.name) {
(*Command)(MusicQueue, Event);
}
}
}
}

25
src/Join.cpp Normal file
View File

@@ -0,0 +1,25 @@
#include <Commands/Join.hpp>
#include <iostream>
#include <dpp/dpp.h>
Join::Join(dpp::snowflake Id) {
dpp::slashcommand Command = dpp::slashcommand("join", "asdf", Id);
dpp::slashcommand Alias = dpp::slashcommand("j", "asdf", Id);
CommandObjectVector.push_back(Command);
CommandObjectVector.push_back(Alias);
}
void Join::operator()(std::list<std::string>& MusicQueue, const dpp::slashcommand_t& Event) {
dpp::guild* g = dpp::find_guild(Event.command.guild_id);
/* Attempt to connect to a voice channel, returns false if we fail to connect. */
if (!g->connect_member_voice(Event.command.get_issuing_user().id)) {
Event.reply("You don't seem to be in a voice channel!");
return;
}
/* Tell the user we joined their channel. */
Event.reply("Joined your channel!");
}

138
src/Play.cpp Normal file
View File

@@ -0,0 +1,138 @@
#include <Commands/Play.hpp>
#include <iostream>
#include <dpp/dpp.h>
#include <oggz/oggz.h>
#include <ogg/ogg.h>
#include <opus/opusfile.h>
Play::Play(dpp::snowflake Id) {
dpp::slashcommand Command = dpp::slashcommand("play", "노래 재생", Id);
Command.add_option(
dpp::command_option(dpp::co_string, "query", "링크 또는 검색어", Id)
);
dpp::slashcommand Alias = dpp::slashcommand("p", "노래 재생", Id);
Alias.add_option(
dpp::command_option(dpp::co_string, "query", "링크 또는 검색어", Id)
);
CommandObjectVector.push_back(Command);
CommandObjectVector.push_back(Alias);
}
void Play::operator()(std::list<std::string>& MusicQueue, const dpp::slashcommand_t& Event) {
if (std::holds_alternative<std::monostate>(Event.get_parameter("query"))) {
/* Get the voice channel the bot is in, in this current guild. */
dpp::voiceconn* v = Event.from->get_voice(Event.command.guild_id);
/* If the voice channel was invalid, or there is an issue with it, then tell the user. */
if (!v || !v->voiceclient || !v->voiceclient->is_ready()) {
Event.reply("There was an issue with getting the voice channel. Make sure I'm in a voice channel!");
return;
}
ogg_sync_state oy;
ogg_stream_state os;
ogg_page og;
ogg_packet op;
OpusHead header;
char *buffer;
FILE *fd;
fd = fopen("../audioplayback.ogg", "rb");
fseek(fd, 0L, SEEK_END);
size_t sz = ftell(fd);
rewind(fd);
ogg_sync_init(&oy);
buffer = ogg_sync_buffer(&oy, sz);
fread(buffer, 1, sz, fd);
ogg_sync_wrote(&oy, sz);
if (ogg_sync_pageout(&oy, &og) != 1) {
fprintf(stderr,"Does not appear to be ogg stream.\n");
exit(1);
}
ogg_stream_init(&os, ogg_page_serialno(&og));
if (ogg_stream_pagein(&os,&og) < 0) {
fprintf(stderr,"Error reading initial page of ogg stream.\n");
exit(1);
}
if (ogg_stream_packetout(&os,&op) != 1) {
fprintf(stderr,"Error reading header packet of ogg stream.\n");
exit(1);
}
/* We must ensure that the ogg stream actually contains opus data */
if (!(op.bytes > 8 && !memcmp("OpusHead", op.packet, 8))) {
fprintf(stderr,"Not an ogg opus stream.\n");
exit(1);
}
/* Parse the header to get stream info */
int err = opus_head_parse(&header, op.packet, op.bytes);
if (err) {
fprintf(stderr,"Not a ogg opus stream\n");
exit(1);
}
/* Now we ensure the encoding is correct for Discord */
if (header.channel_count != 2 && header.input_sample_rate != 48000) {
fprintf(stderr,"Wrong encoding for Discord, must be 48000Hz sample rate with 2 channels.\n");
exit(1);
}
/* Now loop though all the pages and send the packets to the vc */
while (ogg_sync_pageout(&oy, &og) == 1) {
ogg_stream_init(&os, ogg_page_serialno(&og));
if(ogg_stream_pagein(&os,&og)<0) {
fprintf(stderr,"Error reading page of Ogg bitstream data.\n");
exit(1);
}
while (ogg_stream_packetout(&os,&op) != 0) {
/* Read remaining headers */
if (op.bytes > 8 && !memcmp("OpusHead", op.packet, 8)) {
int err = opus_head_parse(&header, op.packet, op.bytes);
if (err) {
fprintf(stderr,"Not a ogg opus stream\n");
exit(1);
}
if (header.channel_count != 2 && header.input_sample_rate != 48000) {
fprintf(stderr,"Wrong encoding for Discord, must be 48000Hz sample rate with 2 channels.\n");
exit(1);
}
continue;
}
/* Skip the opus tags */
if (op.bytes > 8 && !memcmp("OpusTags", op.packet, 8))
continue;
/* Send the audio */
int samples = opus_packet_get_samples_per_frame(op.packet, 48000);
v->voiceclient->send_audio_opus(op.packet, op.bytes, samples / 48);
}
}
/* Cleanup */
ogg_stream_clear(&os);
ogg_sync_clear(&oy);
Event.reply("Finished playing the audio file!");
}
}

14
src/Queue.cpp Normal file
View File

@@ -0,0 +1,14 @@
#include <Commands/Queue.hpp>
#include <iostream>
Queue::Queue(dpp::snowflake Id) {
dpp::slashcommand Command = dpp::slashcommand("queue", "노래 예약 큐 확인", Id);
dpp::slashcommand Alias = dpp::slashcommand("q", "노래 예약 큐 확인", Id);
CommandObjectVector.push_back(Command);
CommandObjectVector.push_back(Alias);
}
void Queue::operator()(std::list<std::string>& MusicQueue, const dpp::slashcommand_t& Event) {
}

27
src/main.cpp Normal file
View File

@@ -0,0 +1,27 @@
#include <BumbleCeepp.hpp>
#include <CommandType.hpp>
#include <iostream>
#include <Commands.hpp>
#include <dpp/nlohmann/json.hpp>
using json = nlohmann::json;
int main() {
json configdocument;
std::ifstream configfile("../config.json");
configfile >> configdocument;
std::unique_ptr<BumbleCeepp> BumbleBee(BumbleCeepp::GetInstance(configdocument["token"]));
Play Command1(BumbleBee->bot->me.id);
Queue Command2(BumbleBee->bot->me.id);
Join Command3(BumbleBee->bot->me.id);
BumbleBee->AddCommand(Command1);
BumbleBee->AddCommand(Command2);
BumbleBee->AddCommand(Command3);
BumbleBee->Start();
return 0;
}