mirror of
https://github.com/HappyTanuki/BumbleCee.git
synced 2025-10-25 17:35:58 +00:00
스트리밍 구현 끝
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,7 +1,6 @@
|
|||||||
build/*
|
build/*
|
||||||
Temp/
|
Temp/
|
||||||
config.json
|
|
||||||
Music
|
Music
|
||||||
*.info.json
|
*.json
|
||||||
yt-dlp
|
yt-dlp
|
||||||
ffmpeg
|
ffmpeg
|
||||||
10
.idea/.gitignore
generated
vendored
Normal file
10
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Environment-dependent path to Maven home directory
|
||||||
|
/mavenHomeManager.xml
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
9
.idea/BumbleCee.iml
generated
Normal file
9
.idea/BumbleCee.iml
generated
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="JAVA_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$" />
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
6
.idea/misc.xml
generated
Normal file
6
.idea/misc.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_23" default="true" project-jdk-name="openjdk-23" project-jdk-type="JavaSDK">
|
||||||
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/BumbleCee.iml" filepath="$PROJECT_DIR$/.idea/BumbleCee.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
3
.vscode/c_cpp_properties.json
vendored
3
.vscode/c_cpp_properties.json
vendored
@@ -3,7 +3,8 @@
|
|||||||
{
|
{
|
||||||
"name": "Linux",
|
"name": "Linux",
|
||||||
"includePath": [
|
"includePath": [
|
||||||
"${workspaceFolder}/**"
|
"${workspaceFolder}/**",
|
||||||
|
"${workspaceFolder}/include"
|
||||||
],
|
],
|
||||||
"defines": [
|
"defines": [
|
||||||
"DDPP_CORO=on"
|
"DDPP_CORO=on"
|
||||||
|
|||||||
7
.vscode/settings.json
vendored
7
.vscode/settings.json
vendored
@@ -97,6 +97,11 @@
|
|||||||
"__tuple": "cpp",
|
"__tuple": "cpp",
|
||||||
"ios": "cpp",
|
"ios": "cpp",
|
||||||
"locale": "cpp",
|
"locale": "cpp",
|
||||||
"queue": "cpp"
|
"queue": "cpp",
|
||||||
|
"hash_map": "cpp",
|
||||||
|
"hash_set": "cpp",
|
||||||
|
"regex": "cpp",
|
||||||
|
"stack": "cpp",
|
||||||
|
"__memory": "cpp"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,32 +5,21 @@ set(BOT_NAME "BumbleCee")
|
|||||||
|
|
||||||
project(${BOT_NAME})
|
project(${BOT_NAME})
|
||||||
aux_source_directory("src" coresrc)
|
aux_source_directory("src" coresrc)
|
||||||
|
aux_source_directory("src/Audio" commands)
|
||||||
aux_source_directory("src/Commands" commands)
|
aux_source_directory("src/Commands" commands)
|
||||||
|
aux_source_directory("src/Queue" settings)
|
||||||
aux_source_directory("src/Settings" settings)
|
aux_source_directory("src/Settings" settings)
|
||||||
|
aux_source_directory("src/Utils" settings)
|
||||||
add_executable(${BOT_NAME} ${coresrc} ${commands} ${settings})
|
add_executable(${BOT_NAME} ${coresrc} ${commands} ${settings})
|
||||||
|
|
||||||
string(ASCII 27 Esc)
|
|
||||||
|
|
||||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||||
|
set(CMAKE_BUILD_TYPE Debug)
|
||||||
set_target_properties(${BOT_NAME} PROPERTIES
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
CXX_STANDARD 20
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
CXX_STANDARD_REQUIRED ON
|
|
||||||
)
|
|
||||||
|
|
||||||
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
|
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
find_package(DPP)
|
find_package(OpenSSL REQUIRED)
|
||||||
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
|
target_include_directories(${BOT_NAME} PUBLIC
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||||
@@ -39,45 +28,13 @@ target_include_directories(${BOT_NAME} PUBLIC
|
|||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(${BOT_NAME}
|
target_link_libraries(${BOT_NAME}
|
||||||
dl
|
|
||||||
dpp
|
dpp
|
||||||
opus
|
opus
|
||||||
opusfile
|
|
||||||
ogg
|
ogg
|
||||||
oggz
|
oggz
|
||||||
mariadbcpp
|
|
||||||
curl
|
|
||||||
${CMAKE_THREAD_LIBS_INIT}
|
${CMAKE_THREAD_LIBS_INIT}
|
||||||
${OPENSSL_CRYPTO_LIBRARY}
|
${OPENSSL_CRYPTO_LIBRARY}
|
||||||
${OPENSSL_SSL_LIBRARY}
|
${OPENSSL_SSL_LIBRARY}
|
||||||
)
|
)
|
||||||
|
|
||||||
if (DPP_FOUND)
|
link_directories(/usr/lib)
|
||||||
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()
|
|
||||||
|
|
||||||
set(CMAKE_CXX_FLAGS "-g")
|
|
||||||
50
include/Audio/MusicPlayManager.hpp
Normal file
50
include/Audio/MusicPlayManager.hpp
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
#pragma once
|
||||||
|
#ifndef _MUSICPLAYMANAGER_HPP_
|
||||||
|
#define _MUSICPLAYMANAGER_HPP_
|
||||||
|
#include <dpp/dpp.h>
|
||||||
|
#include <Queue/MusicQueue.hpp>
|
||||||
|
#include <condition_variable>
|
||||||
|
|
||||||
|
namespace bumbleBee {
|
||||||
|
class MusicPlayManager {
|
||||||
|
public:
|
||||||
|
MusicPlayManager(std::shared_ptr<dpp::cluster> cluster) {
|
||||||
|
this->cluster = cluster;
|
||||||
|
this->queue = std::make_unique<MusicQueue>();
|
||||||
|
|
||||||
|
cluster->on_voice_ready([this](const dpp::voice_ready_t &event){on_voice_ready(event);});
|
||||||
|
cluster->on_voice_track_marker([this](const dpp::voice_track_marker_t &event){on_voice_track_marker(event);});
|
||||||
|
cluster->on_voice_client_disconnect([this](const dpp::voice_client_disconnect_t& event){on_voice_client_disconnect(event);});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief voice_ready 이벤트 인지시 콜백되는 함수
|
||||||
|
* @param event const dpp::voice_ready_t&
|
||||||
|
**/
|
||||||
|
void on_voice_ready(const dpp::voice_ready_t& event);
|
||||||
|
/**
|
||||||
|
* @brief voice_track_marker 이벤트 인지시 콜백되는 함수
|
||||||
|
* @param event const dpp::voice_track_marker_t&
|
||||||
|
**/
|
||||||
|
void on_voice_track_marker(const dpp::voice_track_marker_t& event);
|
||||||
|
/**
|
||||||
|
* @brief voice_client_disconnect 이벤트 인지시 콜백되는 함수
|
||||||
|
* @param event const dpp::voice_client_disconnect_t&
|
||||||
|
**/
|
||||||
|
void on_voice_client_disconnect(const dpp::voice_client_disconnect_t& event);
|
||||||
|
|
||||||
|
void queue_music(const std::shared_ptr<MusicQueueElement> music);
|
||||||
|
|
||||||
|
std::condition_variable queuedCondition;
|
||||||
|
private:
|
||||||
|
std::shared_ptr<dpp::cluster> cluster;
|
||||||
|
/// @brief 음악 큐
|
||||||
|
std::unique_ptr<MusicQueue> queue;
|
||||||
|
|
||||||
|
std::mutex queueEmptyMutex;
|
||||||
|
|
||||||
|
void send_audio_to_voice(const MusicQueueElement& music, const dpp::voice_ready_t &event);
|
||||||
|
void send_audio_to_voice(const MusicQueueElement& music, const dpp::voice_track_marker_t& event);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -4,9 +4,7 @@
|
|||||||
#include <dpp/dpp.h>
|
#include <dpp/dpp.h>
|
||||||
#include <dpp/nlohmann/json.hpp>
|
#include <dpp/nlohmann/json.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <BumbleBeeCommand.hpp>
|
#include <Commands/BumbleBeeCommand.hpp>
|
||||||
#include <MusicQueue.hpp>
|
|
||||||
#include <mariadb/conncpp.hpp>
|
|
||||||
|
|
||||||
namespace bumbleBee {
|
namespace bumbleBee {
|
||||||
/**
|
/**
|
||||||
@@ -16,49 +14,38 @@ namespace bumbleBee {
|
|||||||
class BumbleBee {
|
class BumbleBee {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @fn BumbleBee(nlohmann::json settings)
|
|
||||||
* @brief 생성자
|
* @brief 생성자
|
||||||
**/
|
**/
|
||||||
BumbleBee();
|
BumbleBee();
|
||||||
/**
|
/**
|
||||||
* @fn ~BumbleBee()
|
|
||||||
* @brief 파괴자
|
* @brief 파괴자
|
||||||
* @details BumbleBee의 모든 Property를 책임지고 파괴합니다
|
* @details BumbleBee의 모든 Property를 책임지고 파괴합니다
|
||||||
**/
|
**/
|
||||||
~BumbleBee() {}
|
~BumbleBee() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fn void start()
|
|
||||||
* @brief 봇 시작
|
* @brief 봇 시작
|
||||||
**/
|
**/
|
||||||
void start();
|
void start();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fn void on_slashcommand(const dpp::slashcommand_t& event)
|
|
||||||
* @brief slashcommand 이벤트 인지시 콜백되는 함수
|
* @brief slashcommand 이벤트 인지시 콜백되는 함수
|
||||||
* @param event
|
* @param event const dpp::slashcommand_t&
|
||||||
**/
|
**/
|
||||||
void on_slashcommand(const dpp::slashcommand_t& event);
|
void on_slashcommand(const dpp::slashcommand_t& event);
|
||||||
/**
|
/**
|
||||||
* @fn void on_ready(const dpp::ready_t &event)
|
|
||||||
* @brief ready 이벤트 인지시 콜백되는 함수
|
* @brief ready 이벤트 인지시 콜백되는 함수
|
||||||
* @param event
|
* @param event const dpp::ready_t&
|
||||||
**/
|
**/
|
||||||
void on_ready(const dpp::ready_t &event);
|
void on_ready(const dpp::ready_t& event);
|
||||||
|
|
||||||
/// @brief DPP 기본 클러스터 객체
|
/// @brief DPP 기본 클러스터 객체
|
||||||
std::shared_ptr<dpp::cluster> cluster;
|
std::shared_ptr<dpp::cluster> cluster;
|
||||||
/// @brief 음악 큐
|
|
||||||
std::shared_ptr<MusicQueue> queue;
|
|
||||||
private:
|
private:
|
||||||
/// @brief db 드라이버
|
|
||||||
sql::Driver* dbDriver;
|
|
||||||
/// @brief db 접속 URL
|
|
||||||
std::shared_ptr<sql::SQLString> dbURL;
|
|
||||||
/// @brief db 접속 속성
|
|
||||||
std::shared_ptr<sql::Properties> dbProperties;
|
|
||||||
/// @brief Command 목록
|
/// @brief Command 목록
|
||||||
std::vector<std::shared_ptr<commands::ICommand>> commands;
|
std::unordered_map<std::string, std::shared_ptr<commands::ICommand>> commands;
|
||||||
|
/// @brief voiceclient 관련 event 처리기 <guild id, 각 길드별 MusicPlayManager 인스턴스>
|
||||||
|
std::shared_ptr<MusicPlayManager> musicManager;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#ifndef _BUMBLEBEECOMMAND_HPP_
|
|
||||||
#define _BUMBLEBEECOMMAND_HPP_
|
|
||||||
#include <dpp/dpp.h>
|
|
||||||
#include <MusicQueue.hpp>
|
|
||||||
|
|
||||||
namespace bumbleBee::commands {
|
|
||||||
class ICommand {
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* @brief 기본 생성자
|
|
||||||
* @param botID 명령어 등록을 위한 봇 아이디
|
|
||||||
* @param queue 음악이 저장되어 있는 큐
|
|
||||||
**/
|
|
||||||
ICommand(dpp::snowflake botID, std::weak_ptr<MusicQueue> queue) {
|
|
||||||
this->botID = botID;
|
|
||||||
this->queue = queue;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @brief 명령어 호출 시에 콜백될 메소드
|
|
||||||
* @param event dpp::slashcommand_t
|
|
||||||
**/
|
|
||||||
virtual void operator()(const dpp::slashcommand_t &event){};
|
|
||||||
|
|
||||||
/// @brief 봇 명령어들의 이름과 별명들을 저장하는 벡터
|
|
||||||
std::vector<dpp::slashcommand> nameAndAliases;
|
|
||||||
|
|
||||||
private:
|
|
||||||
/// @brief 봇 ID
|
|
||||||
dpp::snowflake botID;
|
|
||||||
/// @brief 음악 큐에 대한 약한 포인터
|
|
||||||
std::weak_ptr<MusicQueue> queue;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 명령어 별명 추가
|
|
||||||
* @param name 명령어 이름
|
|
||||||
* @param description 명령어 설명
|
|
||||||
**/
|
|
||||||
void addCommandAliase(std::string name, std::string description) {
|
|
||||||
nameAndAliases.push_back(dpp::slashcommand(name, description, botID));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 명령어 인자가 없는 명령어의 boilerplate 대체 매크로
|
|
||||||
* @param name 명령어 이름 및 클래스명
|
|
||||||
* @param alias 명령어 별명
|
|
||||||
* @param description 명령어 설명
|
|
||||||
**/
|
|
||||||
#define _DECLARE_BUMBLEBEE_COMMAND_one_ALIAS(name, alias, description) \
|
|
||||||
namespace bumbleBee::commands { \
|
|
||||||
class name : public ICommand { \
|
|
||||||
public: \
|
|
||||||
name (dpp::snowflake botID, std::weak_ptr<MusicQueue> q) \
|
|
||||||
: ICommand(botID, q) { \
|
|
||||||
dpp::slashcommand command = dpp::slashcommand(#name, description, botID); \
|
|
||||||
dpp::slashcommand aliasCommand = dpp::slashcommand(alias, description, botID); \
|
|
||||||
nameAndAliases.push_back(command); \
|
|
||||||
nameAndAliases.push_back(aliasCommand); \
|
|
||||||
} \
|
|
||||||
virtual void operator()(const dpp::slashcommand_t &event) override; \
|
|
||||||
}; \
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 명령어 인자를 하나 갖는 명령어의 boilerplate 대체 매크로
|
|
||||||
* @param name 명령어 이름 및 클래스명
|
|
||||||
* @param alias 명령어 별명
|
|
||||||
* @param description 명령어 설명
|
|
||||||
* @param option_name 명령어 인자 이름
|
|
||||||
* @param option_desc 명령어 인자 설명
|
|
||||||
**/
|
|
||||||
#define _DECLARE_BUMBLEBEE_COMMAND_one_PARAM_one_ALIAS(name, alias, description, option_name, option_desc) \
|
|
||||||
namespace bumbleBee::commands { \
|
|
||||||
class name : public ICommand { \
|
|
||||||
public: \
|
|
||||||
name (dpp::snowflake botID, std::weak_ptr<MusicQueue> q) \
|
|
||||||
: ICommand(botID, q) { \
|
|
||||||
dpp::slashcommand command = dpp::slashcommand(#name, description, botID); \
|
|
||||||
dpp::slashcommand aliasCommand = dpp::slashcommand(alias, description, botID); \
|
|
||||||
command.add_option( \
|
|
||||||
dpp::command_option(dpp::co_string, option_name, option_desc, botID) \
|
|
||||||
); \
|
|
||||||
aliasCommand.add_option( \
|
|
||||||
dpp::command_option(dpp::co_string, option_name, option_desc, botID) \
|
|
||||||
); \
|
|
||||||
nameAndAliases.push_back(command); \
|
|
||||||
nameAndAliases.push_back(aliasCommand); \
|
|
||||||
} \
|
|
||||||
virtual void operator()(const dpp::slashcommand_t &event) override; \
|
|
||||||
}; \
|
|
||||||
}
|
|
||||||
|
|
||||||
_DECLARE_BUMBLEBEE_COMMAND_one_PARAM_one_ALIAS(Delete, "d", "큐의 해당하는 번호의 노래를 지웁니다", "pos", "큐 번호")
|
|
||||||
_DECLARE_BUMBLEBEE_COMMAND_one_ALIAS(Leave, "l", "음성 채팅방을 떠납니다")
|
|
||||||
_DECLARE_BUMBLEBEE_COMMAND_one_PARAM_one_ALIAS(Play, "p", "노래 재생", "query", "링크 또는 검색어")
|
|
||||||
_DECLARE_BUMBLEBEE_COMMAND_one_ALIAS(Queue, "q", "노래 예약 큐를 출력합니다")
|
|
||||||
_DECLARE_BUMBLEBEE_COMMAND_one_ALIAS(Repeat, "r", "반복을 켜거나 끕니다")
|
|
||||||
_DECLARE_BUMBLEBEE_COMMAND_one_ALIAS(Skip, "s", "현재 재생중인 곡을 스킵합니다")
|
|
||||||
|
|
||||||
#endif
|
|
||||||
70
include/Commands/BumbleBeeCommand.hpp
Normal file
70
include/Commands/BumbleBeeCommand.hpp
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
#pragma once
|
||||||
|
#ifndef _BUMBLEBEECOMMAND_HPP_
|
||||||
|
#define _BUMBLEBEECOMMAND_HPP_
|
||||||
|
#include <dpp/dpp.h>
|
||||||
|
#include <Audio/MusicPlayManager.hpp>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace bumbleBee::commands {
|
||||||
|
class ICommand : public dpp::slashcommand {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief 기본 생성자
|
||||||
|
* @param botID 봇 아이디
|
||||||
|
* @param manager 음악재생 매니저
|
||||||
|
**/
|
||||||
|
ICommand(dpp::snowflake botID, std::shared_ptr<MusicPlayManager> manager) {
|
||||||
|
this->botID = botID;
|
||||||
|
this->musicManager = manager;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @brief 명령어 호출 시에 콜백될 메소드
|
||||||
|
* @param event dpp::slashcommand_t
|
||||||
|
**/
|
||||||
|
virtual void execute(const dpp::slashcommand_t &event){};
|
||||||
|
|
||||||
|
/// @brief 명령어 별명
|
||||||
|
std::vector<std::string> aliases;
|
||||||
|
private:
|
||||||
|
/// @brief 봇 ID
|
||||||
|
dpp::snowflake botID;
|
||||||
|
protected:
|
||||||
|
/// @brief 음악재생 매니저
|
||||||
|
std::shared_ptr<MusicPlayManager> musicManager;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/// @brief concrete class에서 구현해야 하는 init 이벤트트
|
||||||
|
virtual void init() = 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 명령어 인자가 없는 명령어의 boilerplate 대체 매크로
|
||||||
|
* @param name 명령어 이름 및 클래스명
|
||||||
|
* @param description 명령어 설명
|
||||||
|
**/
|
||||||
|
#define _DECLARE_BUMBLEBEE_COMMAND(CLASS, NAME, DESCRIPTION) \
|
||||||
|
namespace bumbleBee::commands { \
|
||||||
|
class CLASS : public ICommand { \
|
||||||
|
public: \
|
||||||
|
CLASS (dpp::snowflake botID, std::shared_ptr<MusicPlayManager> manager) \
|
||||||
|
: ICommand(botID, manager) { \
|
||||||
|
name = #NAME; \
|
||||||
|
description = DESCRIPTION; \
|
||||||
|
init(); \
|
||||||
|
} \
|
||||||
|
virtual void execute(const dpp::slashcommand_t &event) override; \
|
||||||
|
protected: \
|
||||||
|
virtual void init() override; \
|
||||||
|
}; \
|
||||||
|
}
|
||||||
|
|
||||||
|
_DECLARE_BUMBLEBEE_COMMAND(Delete, d, "큐의 해당하는 번호의 노래를 지웁니다")
|
||||||
|
_DECLARE_BUMBLEBEE_COMMAND(Leave, l, "음성 채팅방을 떠납니다")
|
||||||
|
_DECLARE_BUMBLEBEE_COMMAND(Play, p, "노래 재생")
|
||||||
|
_DECLARE_BUMBLEBEE_COMMAND(Queue, q, "노래 예약 큐를 출력합니다")
|
||||||
|
_DECLARE_BUMBLEBEE_COMMAND(Repeat, r, "반복을 켜거나 끕니다")
|
||||||
|
_DECLARE_BUMBLEBEE_COMMAND(Skip, s, "현재 재생중인 곡을 스킵합니다")
|
||||||
|
_DECLARE_BUMBLEBEE_COMMAND(Shuffle, shuffle, "큐를 섞습니다")
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#ifndef _MUSICPLAYMANAGER_HPP_
|
|
||||||
#define _MUSICPLAYMANAGER_HPP_
|
|
||||||
#include <dpp/dpp.h>
|
|
||||||
|
|
||||||
namespace BumbleBee {
|
|
||||||
class MusicPlayManager {
|
|
||||||
public:
|
|
||||||
MusicPlayManager(std::shared_ptr<dpp::cluster> cluster) {
|
|
||||||
this->cluster = cluster;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
std::shared_ptr<dpp::cluster> cluster;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#ifndef _MUSICQUEUE_HPP_
|
|
||||||
#define _MUSICQUEUE_HPP_
|
|
||||||
#include <memory>
|
|
||||||
#include <functional>
|
|
||||||
#include <condition_variable>
|
|
||||||
#include <list>
|
|
||||||
#include <dpp/dpp.h>
|
|
||||||
|
|
||||||
namespace bumbleBee {
|
|
||||||
|
|
||||||
class MusicQueueElement {
|
|
||||||
public:
|
|
||||||
MusicQueueElement(
|
|
||||||
dpp::message originalResponse,
|
|
||||||
std::string id,
|
|
||||||
std::string url,
|
|
||||||
FILE* stream) :
|
|
||||||
|
|
||||||
originalResponse(originalResponse), id(id), url(url), stream(stream) {}
|
|
||||||
dpp::message originalResponse;
|
|
||||||
std::string id;
|
|
||||||
std::string url;
|
|
||||||
FILE* stream;
|
|
||||||
};
|
|
||||||
|
|
||||||
class MusicQueue {
|
|
||||||
public:
|
|
||||||
MusicQueue() {
|
|
||||||
currentPlayingPosition = queue.begin();
|
|
||||||
repeat = false;
|
|
||||||
}
|
|
||||||
void enqueue(std::shared_ptr<MusicQueueElement> Element);
|
|
||||||
std::shared_ptr<MusicQueueElement> dequeue();
|
|
||||||
std::shared_ptr<MusicQueueElement> findById(std::string id);
|
|
||||||
std::weak_ptr<MusicQueueElement> nowplaying();
|
|
||||||
std::weak_ptr<MusicQueueElement> next_music();
|
|
||||||
std::weak_ptr<MusicQueueElement> jump_to_index(int idx);
|
|
||||||
|
|
||||||
bool repeat;
|
|
||||||
std::function<void()> on_queue_added;
|
|
||||||
private:
|
|
||||||
std::condition_variable queueItemAdded;
|
|
||||||
std::mutex queueMutex;
|
|
||||||
std::list<std::shared_ptr<MusicQueueElement>> queue;
|
|
||||||
std::list<std::shared_ptr<MusicQueueElement>>::iterator currentPlayingPosition;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
36
include/Queue/MusicQueue.hpp
Normal file
36
include/Queue/MusicQueue.hpp
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#pragma once
|
||||||
|
#ifndef _MUSICQUEUE_HPP_
|
||||||
|
#define _MUSICQUEUE_HPP_
|
||||||
|
#include <memory>
|
||||||
|
#include <functional>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <list>
|
||||||
|
#include <dpp/dpp.h>
|
||||||
|
#include <Queue/MusicQueueElement.hpp>
|
||||||
|
|
||||||
|
namespace bumbleBee {
|
||||||
|
|
||||||
|
class MusicQueue {
|
||||||
|
public:
|
||||||
|
MusicQueue() {
|
||||||
|
queue = std::list<std::shared_ptr<MusicQueueElement>>();
|
||||||
|
currentPlayingPosition = queue.begin();
|
||||||
|
repeat = false;
|
||||||
|
}
|
||||||
|
void enqueue(std::shared_ptr<MusicQueueElement> Element);
|
||||||
|
std::shared_ptr<MusicQueueElement> dequeue();
|
||||||
|
std::list<std::shared_ptr<MusicQueueElement>>::iterator findById(std::string id);
|
||||||
|
std::shared_ptr<MusicQueueElement> nowplaying();
|
||||||
|
std::list<std::shared_ptr<MusicQueueElement>>::iterator next_music();
|
||||||
|
std::shared_ptr<MusicQueueElement> jump_to_index(int idx);
|
||||||
|
|
||||||
|
bool repeat;
|
||||||
|
|
||||||
|
std::list<std::shared_ptr<MusicQueueElement>>::iterator currentPlayingPosition;
|
||||||
|
std::list<std::shared_ptr<MusicQueueElement>> queue;
|
||||||
|
private:
|
||||||
|
std::mutex queueMutex;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
21
include/Queue/MusicQueueElement.hpp
Normal file
21
include/Queue/MusicQueueElement.hpp
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
#ifndef _MUSICQUEUEELEMENT_HPP_
|
||||||
|
#define _MUSICQUEUEELEMENT_HPP_
|
||||||
|
#include <dpp/dpp.h>
|
||||||
|
|
||||||
|
namespace bumbleBee {
|
||||||
|
|
||||||
|
class MusicQueueElement {
|
||||||
|
public:
|
||||||
|
MusicQueueElement(
|
||||||
|
std::string id,
|
||||||
|
std::string query,
|
||||||
|
dpp::user issuingUser) :
|
||||||
|
id(id), query(query), issuingUser(issuingUser) {}
|
||||||
|
|
||||||
|
const std::string id;
|
||||||
|
const std::string query;
|
||||||
|
const dpp::user issuingUser;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -1,30 +1,37 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#ifndef _SETTINGSMANAGER_HPP_
|
#ifndef _SETTINGSMANAGER_HPP_
|
||||||
#define _SETTINGSMANAGER_HPP_
|
#define _SETTINGSMANAGER_HPP_
|
||||||
#include <string>
|
#include <dpp/dpp.h>
|
||||||
#include <dpp/nlohmann/json.hpp>
|
|
||||||
#include <fstream>
|
#define _DECLARE_DEFAULT_ACCESSER_STATIC_VARIABLE(type, name, Name)\
|
||||||
|
private:\
|
||||||
|
static type name;\
|
||||||
|
public:\
|
||||||
|
static type get##Name() {return name;}\
|
||||||
|
static void set##Name(const type& value) {name = value; saveToFile();}
|
||||||
|
|
||||||
namespace bumbleBee {
|
namespace bumbleBee {
|
||||||
|
/// @brief 모든 설정은 이 객체를 통해 스태틱하게 제공됨.
|
||||||
class settingsManager {
|
class settingsManager {
|
||||||
public:
|
|
||||||
/// @brief 봇 토큰
|
/// @brief 봇 토큰
|
||||||
static std::string TOKEN;
|
_DECLARE_DEFAULT_ACCESSER_STATIC_VARIABLE(std::string, TOKEN, TOKEN)
|
||||||
/// @brief yt-dlp 실행 명령어
|
/// @brief yt-dlp 실행 명령어
|
||||||
static std::string YTDLP_CMD;
|
_DECLARE_DEFAULT_ACCESSER_STATIC_VARIABLE(std::string, YTDLP_CMD, YTDLP_CMD)
|
||||||
/// @brief ffmpeg 실행 명령어
|
/// @brief ffmpeg 실행 명령어
|
||||||
static std::string FFMPEG_CMD;
|
_DECLARE_DEFAULT_ACCESSER_STATIC_VARIABLE(std::string, FFMPEG_CMD, FFMPEG_CMD)
|
||||||
/// @brief db접속 url
|
/// @brief 로그레벨
|
||||||
static std::string DBURL;
|
_DECLARE_DEFAULT_ACCESSER_STATIC_VARIABLE(dpp::loglevel, LOGLEVEL, LOGLEVEL)
|
||||||
/// @brief db접속 유저
|
/// @brief 이전에 있던 명령을 지우고 등록할지 선택합니다.
|
||||||
static std::string DBUSER;
|
_DECLARE_DEFAULT_ACCESSER_STATIC_VARIABLE(bool, CLCOMMAND, CLCOMMAND)
|
||||||
/// @brief db접속 비밀번호
|
public:
|
||||||
static std::string DBPASSWORD;
|
/// @brief 설정 로드하기, 설정은 이 load()를 부르기 전까지는 적절하지 못한 값을 가지고 있음.
|
||||||
|
/// @return 로드 성공 시 true, 실패 시 false 반환.
|
||||||
|
static bool load();
|
||||||
static void load();
|
/// @brief 설정 변경사항 저장
|
||||||
|
|
||||||
static void saveToFile();
|
static void saveToFile();
|
||||||
|
/// @brief 토큰이 유효한지 체크합니다.
|
||||||
|
/// @return 유효한 토큰이면 true, 아니면 false를 반환합니다.
|
||||||
|
static bool validateToken();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -6,18 +6,15 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <dpp/dpp.h>
|
#include <dpp/dpp.h>
|
||||||
#include <MusicQueue.hpp>
|
#include <Queue/MusicQueue.hpp>
|
||||||
|
|
||||||
#define WORKER_COUNT 5
|
|
||||||
|
|
||||||
namespace bumbleBee {
|
namespace bumbleBee {
|
||||||
/// @brief 싱글톤 멀티스레딩 다운로드 매니저
|
/// @brief 싱글톤 멀티스레딩 다운로드 매니저
|
||||||
class AsyncDownloadManager {
|
class [[deprecated]] AsyncDownloadManager {
|
||||||
public:
|
public:
|
||||||
static AsyncDownloadManager& getInstance(int worker_count, std::weak_ptr<dpp::cluster> weak_cluster, std::shared_ptr<bumbleBee::MusicQueue> musicQueue) {
|
static AsyncDownloadManager& getInstance(int worker_count, std::weak_ptr<dpp::cluster> weak_cluster) {
|
||||||
static AsyncDownloadManager dl(worker_count);
|
static AsyncDownloadManager dl(worker_count);
|
||||||
dl.weak_cluster = weak_cluster;
|
dl.weak_cluster = weak_cluster;
|
||||||
dl.musicQueue = musicQueue;
|
|
||||||
return dl;
|
return dl;
|
||||||
}
|
}
|
||||||
void enqueue(std::pair<std::string, dpp::message> query) {
|
void enqueue(std::pair<std::string, dpp::message> query) {
|
||||||
@@ -55,7 +52,6 @@ private:
|
|||||||
std::condition_variable dlQueueCondition;
|
std::condition_variable dlQueueCondition;
|
||||||
std::mutex dlQueueMutex;
|
std::mutex dlQueueMutex;
|
||||||
std::weak_ptr<dpp::cluster> weak_cluster;
|
std::weak_ptr<dpp::cluster> weak_cluster;
|
||||||
std::shared_ptr<bumbleBee::MusicQueue> musicQueue;
|
|
||||||
std::vector<std::thread> worker_thread;
|
std::vector<std::thread> worker_thread;
|
||||||
bool terminate;
|
bool terminate;
|
||||||
};
|
};
|
||||||
@@ -19,7 +19,7 @@ public:
|
|||||||
|
|
||||||
static void validateYTDLPFFMPEGBinary(std::shared_ptr<dpp::cluster> cluster) {
|
static void validateYTDLPFFMPEGBinary(std::shared_ptr<dpp::cluster> cluster) {
|
||||||
cluster->log(dpp::ll_info, "Checking if yt-dlp and ffmpeg is available...");
|
cluster->log(dpp::ll_info, "Checking if yt-dlp and ffmpeg is available...");
|
||||||
std::queue<std::string> result = ConsoleUtils::getResultFromCommand(settingsManager::FFMPEG_CMD + " -version");
|
std::queue<std::string> result = ConsoleUtils::getResultFromCommand(settingsManager::getFFMPEG_CMD() + " -version");
|
||||||
std::string front = result.front();
|
std::string front = result.front();
|
||||||
if (front[0] != 'f' ||
|
if (front[0] != 'f' ||
|
||||||
front[1] != 'f' ||
|
front[1] != 'f' ||
|
||||||
@@ -40,8 +40,9 @@ public:
|
|||||||
system("tar -xf ffmpeg-master-latest-linux64-gpl.tar.xz");
|
system("tar -xf ffmpeg-master-latest-linux64-gpl.tar.xz");
|
||||||
system("rm ffmpeg-master-latest-linux64-gpl.tar.xz");
|
system("rm ffmpeg-master-latest-linux64-gpl.tar.xz");
|
||||||
system("mv ffmpeg-master-latest-linux64-gpl ffmpeg");
|
system("mv ffmpeg-master-latest-linux64-gpl ffmpeg");
|
||||||
|
settingsManager::setFFMPEG_CMD("./ffmpeg/bin/ffmpeg");
|
||||||
}
|
}
|
||||||
result = ConsoleUtils::getResultFromCommand(settingsManager::YTDLP_CMD + " --version");
|
result = ConsoleUtils::getResultFromCommand(settingsManager::getYTDLP_CMD() + " --version");
|
||||||
front = result.front();
|
front = result.front();
|
||||||
if ((front[0]-'0' < 0 || front[0]-'0' > 9) ||
|
if ((front[0]-'0' < 0 || front[0]-'0' > 9) ||
|
||||||
(front[1]-'0' < 0 || front[1]-'0' > 9) ||
|
(front[1]-'0' < 0 || front[1]-'0' > 9) ||
|
||||||
@@ -58,6 +59,7 @@ public:
|
|||||||
|
|
||||||
system("curl -LO https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp");
|
system("curl -LO https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp");
|
||||||
system("chmod +x ./yt-dlp");
|
system("chmod +x ./yt-dlp");
|
||||||
|
settingsManager::setYTDLP_CMD("./yt-dlp");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
68
src/Audio/MusicPlayManager.cpp
Normal file
68
src/Audio/MusicPlayManager.cpp
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
#include <Audio/MusicPlayManager.hpp>
|
||||||
|
#include <ogg/ogg.h>
|
||||||
|
#include <oggz/oggz.h>
|
||||||
|
|
||||||
|
namespace bumbleBee {
|
||||||
|
|
||||||
|
void MusicPlayManager::on_voice_ready(const dpp::voice_ready_t& event) {
|
||||||
|
std::unique_lock<std::mutex> queueEmptyLock(queueEmptyMutex);
|
||||||
|
queuedCondition.wait(queueEmptyLock, [&]{
|
||||||
|
return queue->queue.size() != 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
auto np = queue->nowplaying();
|
||||||
|
auto music = *np;
|
||||||
|
|
||||||
|
std::string command = "./streamOpus.sh ./yt-dlp ffmpeg https://youtu.be/";
|
||||||
|
command += music.id;
|
||||||
|
|
||||||
|
OGGZ* og = oggz_open_stdio(popen(command.c_str(), "r"), OGGZ_READ);
|
||||||
|
|
||||||
|
oggz_set_read_callback(
|
||||||
|
og, -1,
|
||||||
|
[](OGGZ *oggz, oggz_packet *packet, long serialno, void *user_data) {
|
||||||
|
auto voiceConn = (dpp::discord_voice_client *)user_data;
|
||||||
|
|
||||||
|
voiceConn->send_audio_opus(packet->op.packet, packet->op.bytes);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
},
|
||||||
|
(void *)event.voice_client
|
||||||
|
);
|
||||||
|
|
||||||
|
while (event.voice_client && !event.voice_client->terminating) {
|
||||||
|
static const constexpr long CHUNK_READ = BUFSIZ * 2;
|
||||||
|
|
||||||
|
const long read_bytes = oggz_read(og, CHUNK_READ);
|
||||||
|
|
||||||
|
/* break on eof */
|
||||||
|
if (!read_bytes) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//event.from->creator->log(dpp::ll_info, std::string("Sending ") + music.id + " complete!");
|
||||||
|
oggz_close(og);
|
||||||
|
|
||||||
|
event.voice_client->insert_marker("end");
|
||||||
|
|
||||||
|
queueEmptyLock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MusicPlayManager::on_voice_track_marker(const dpp::voice_track_marker_t& event) {
|
||||||
|
queue->next_music();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MusicPlayManager::on_voice_client_disconnect(const dpp::voice_client_disconnect_t& event) {
|
||||||
|
event.voice_client->stop_audio();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MusicPlayManager::queue_music(const std::shared_ptr<MusicQueueElement> music) {
|
||||||
|
queue->enqueue(music);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MusicPlayManager::send_audio_to_voice(const MusicQueueElement& music, const dpp::voice_ready_t &event) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -2,39 +2,80 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <Settings/SettingsManager.hpp>
|
#include <Settings/SettingsManager.hpp>
|
||||||
#include <Utils/VersionsCheckUtils.hpp>
|
#include <Utils/VersionsCheckUtils.hpp>
|
||||||
|
#include <Audio/MusicPlayManager.hpp>
|
||||||
|
#include <Commands/BumbleBeeCommand.hpp>
|
||||||
|
|
||||||
namespace bumbleBee{
|
namespace bumbleBee{
|
||||||
BumbleBee::BumbleBee() {
|
BumbleBee::BumbleBee() {
|
||||||
settingsManager::load();
|
if (!settingsManager::load()) {
|
||||||
this->cluster = std::make_shared<dpp::cluster>(settingsManager::TOKEN);
|
std::cout << "Please configure confing.json" << std::endl;
|
||||||
dbDriver = sql::mariadb::get_driver_instance();
|
exit(1);
|
||||||
this->dbURL = std::make_shared<sql::SQLString>(settingsManager::DBURL);
|
}
|
||||||
sql::Properties pro({
|
|
||||||
{"user", std::string(settingsManager::DBUSER)},
|
|
||||||
{"password", std::string(settingsManager::DBPASSWORD)}
|
|
||||||
});
|
|
||||||
this->dbProperties = std::make_shared<sql::Properties>(pro);
|
|
||||||
|
|
||||||
cluster->on_log(dpp::utility::cout_logger());
|
cluster = std::make_shared<dpp::cluster>(settingsManager::getTOKEN());
|
||||||
|
|
||||||
|
cluster->on_log([](const dpp::log_t& event) {
|
||||||
|
if (event.severity >= settingsManager::getLOGLEVEL()) {
|
||||||
|
std::cout << "[" << dpp::utility::current_date_time() << "] " << dpp::utility::loglevel(event.severity) << ": " << event.message << "\n";
|
||||||
|
}
|
||||||
|
});
|
||||||
cluster->on_slashcommand([this](const dpp::slashcommand_t& event){on_slashcommand(event);});
|
cluster->on_slashcommand([this](const dpp::slashcommand_t& event){on_slashcommand(event);});
|
||||||
cluster->on_ready([this](const dpp::ready_t &event){on_ready(event);});
|
cluster->on_ready([this](const dpp::ready_t &event){on_ready(event);});
|
||||||
|
|
||||||
queue = std::make_shared<MusicQueue>();
|
|
||||||
|
|
||||||
VersionsCheckUtils::validateYTDLPFFMPEGBinary(cluster);
|
VersionsCheckUtils::validateYTDLPFFMPEGBinary(cluster);
|
||||||
VersionsCheckUtils::updateytdlp(cluster);
|
VersionsCheckUtils::updateytdlp(cluster);
|
||||||
|
|
||||||
|
musicManager = std::make_shared<MusicPlayManager>(cluster);
|
||||||
|
|
||||||
|
commands["d"] = std::make_shared<commands::Delete> (cluster->cluster_id, musicManager);
|
||||||
|
commands["l"] = std::make_shared<commands::Leave> (cluster->cluster_id, musicManager);
|
||||||
|
commands["p"] = std::make_shared<commands::Play> (cluster->cluster_id, musicManager);
|
||||||
|
commands["q"] = std::make_shared<commands::Queue> (cluster->cluster_id, musicManager);
|
||||||
|
commands["r"] = std::make_shared<commands::Repeat> (cluster->cluster_id, musicManager);
|
||||||
|
commands["s"] = std::make_shared<commands::Skip> (cluster->cluster_id, musicManager);
|
||||||
|
|
||||||
|
for (auto command : commands) {
|
||||||
|
for (auto aliase : command.second->aliases) {
|
||||||
|
commands[aliase] = std::shared_ptr<commands::ICommand>(command.second);
|
||||||
|
commands[aliase]->set_name(aliase);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BumbleBee::start() { this->cluster->start(dpp::st_wait); }
|
void BumbleBee::start() { this->cluster->start(dpp::st_wait); }
|
||||||
|
|
||||||
void BumbleBee::on_slashcommand(const dpp::slashcommand_t &event) {
|
void BumbleBee::on_slashcommand(const dpp::slashcommand_t &event) {
|
||||||
for (auto command : commands)
|
if (commands.find(event.command.get_command_name()) != commands.end()) {
|
||||||
for (auto alias : command->nameAndAliases)
|
event.thinking();
|
||||||
if (event.command.get_command_name() == alias.name)
|
auto command = commands.at(event.command.get_command_name());
|
||||||
(*command)(event);
|
std::thread t([](const dpp::slashcommand_t &event, std::shared_ptr<commands::ICommand> command){
|
||||||
|
command->execute(event);
|
||||||
|
}, event, command);
|
||||||
|
t.detach();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BumbleBee::on_ready(const dpp::ready_t &event) {
|
void BumbleBee::on_ready(const dpp::ready_t &event) {
|
||||||
cluster->log(dpp::loglevel::ll_info, "Bot ready.");
|
cluster->log(dpp::loglevel::ll_info, "Bot ready.");
|
||||||
|
|
||||||
|
if (event.guilds.size() == 0) {
|
||||||
|
cluster->log(dpp::loglevel::ll_info, "Bot is not on any server! Please invite this bot to any server.");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dpp::run_once<struct register_bot_commands>()) {
|
||||||
|
if (settingsManager::getCLCOMMAND()) {
|
||||||
|
cluster->log(dpp::loglevel::ll_info, "Clear Pre-installed commands");
|
||||||
|
cluster->global_bulk_command_delete([](const dpp::confirmation_callback_t &t){
|
||||||
|
std::cout << "cleared Pre-installed commands. Please restart Bot" << std::endl;
|
||||||
|
settingsManager::setCLCOMMAND(false);
|
||||||
|
exit(0);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (auto command : commands)
|
||||||
|
cluster->global_command_create(*command.second);
|
||||||
|
}
|
||||||
|
cluster->log(dpp::loglevel::ll_info, "Command created.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,11 @@
|
|||||||
#include <BumbleBeeCommand.hpp>
|
#include <Commands/BumbleBeeCommand.hpp>
|
||||||
|
|
||||||
namespace bumbleBee::commands {
|
namespace bumbleBee::commands {
|
||||||
void Delete::operator()(const dpp::slashcommand_t &event) {
|
void Delete::execute(const dpp::slashcommand_t &event) {
|
||||||
|
event.edit_original_response(dpp::message("delete"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Delete::init() {
|
||||||
|
aliases.push_back("delete");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
10
src/Commands/Leave.cpp
Normal file
10
src/Commands/Leave.cpp
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#include <Commands/BumbleBeeCommand.hpp>
|
||||||
|
|
||||||
|
namespace bumbleBee::commands {
|
||||||
|
void Leave::execute(const dpp::slashcommand_t &event) {
|
||||||
|
event.edit_original_response(dpp::message("leave"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Leave::init() {
|
||||||
|
}
|
||||||
|
}
|
||||||
70
src/Commands/Play.cpp
Normal file
70
src/Commands/Play.cpp
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
#include <Commands/BumbleBeeCommand.hpp>
|
||||||
|
#include <Utils/ConsoleUtils.hpp>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
|
namespace bumbleBee::commands {
|
||||||
|
void Play::execute(const dpp::slashcommand_t &event) {
|
||||||
|
dpp::guild *g = dpp::find_guild(event.command.guild_id);
|
||||||
|
|
||||||
|
if (!g) { //wtf?
|
||||||
|
event.edit_original_response(dpp::message("GUILD NOT FOUND!! WHAT IS THIS SORCERY??"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (std::holds_alternative<std::monostate>(event.get_parameter("query")))
|
||||||
|
{
|
||||||
|
event.reply("노래를 재생하려면 검색어 또는 링크를 입력해 주십시오.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!event.from->get_voice(event.command.guild_id) && !g->connect_member_voice(event.command.usr.id)) {
|
||||||
|
event.edit_original_response(dpp::message("노래를 재생할 음성 채팅방에 먼저 참가하고 신청해야 합니다!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::string query = std::get<std::string>(event.get_parameter("query"));
|
||||||
|
|
||||||
|
std::queue<std::string> ids = ConsoleUtils::getResultFromCommand("./yt-dlp --default-search ytsearch --flat-playlist --skip-download --quiet --ignore-errors --print id " + query);
|
||||||
|
|
||||||
|
std::queue<MusicQueueElement> musics;
|
||||||
|
|
||||||
|
dpp::message origMsg;
|
||||||
|
|
||||||
|
if (ids.size() >= 2) {
|
||||||
|
event.from->creator->log(dpp::ll_info, "Playlist detected.");
|
||||||
|
while (!ids.empty()) {
|
||||||
|
if (ids.front() == "") {
|
||||||
|
ids.pop();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
event.from->creator->log(dpp::ll_info, "Enqueuing " + ids.front());
|
||||||
|
|
||||||
|
MusicQueueElement music(
|
||||||
|
ids.front(),
|
||||||
|
query,
|
||||||
|
event.command.usr
|
||||||
|
);
|
||||||
|
|
||||||
|
musics.push(music);
|
||||||
|
ids.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MusicQueueElement music(
|
||||||
|
ids.front(),
|
||||||
|
query,
|
||||||
|
event.command.usr
|
||||||
|
);
|
||||||
|
musics.push(music);
|
||||||
|
|
||||||
|
while (!musics.empty()) {
|
||||||
|
auto element = musics.front();
|
||||||
|
musicManager->queue_music(std::make_shared<MusicQueueElement>(element));
|
||||||
|
musics.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
event.edit_original_response(dpp::message("play"));
|
||||||
|
musicManager->queuedCondition.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Play::init() {
|
||||||
|
add_option(dpp::command_option(dpp::co_string, "query", "링크 또는 검색어", true));
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/Commands/Queue.cpp
Normal file
10
src/Commands/Queue.cpp
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#include <Commands/BumbleBeeCommand.hpp>
|
||||||
|
|
||||||
|
namespace bumbleBee::commands {
|
||||||
|
void Queue::execute(const dpp::slashcommand_t &event) {
|
||||||
|
event.edit_original_response(dpp::message("queue"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Queue::init() {
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/Commands/Repeat.cpp
Normal file
10
src/Commands/Repeat.cpp
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#include <Commands/BumbleBeeCommand.hpp>
|
||||||
|
|
||||||
|
namespace bumbleBee::commands {
|
||||||
|
void Repeat::execute(const dpp::slashcommand_t &event) {
|
||||||
|
event.edit_original_response(dpp::message("repeat"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Repeat::init() {
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/Commands/Shuffle.cpp
Normal file
10
src/Commands/Shuffle.cpp
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#include <Commands/BumbleBeeCommand.hpp>
|
||||||
|
|
||||||
|
namespace bumbleBee::commands {
|
||||||
|
void Shuffle::execute(const dpp::slashcommand_t &event) {
|
||||||
|
event.edit_original_response(dpp::message("shuffle"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shuffle::init() {
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/Commands/Skip.cpp
Normal file
10
src/Commands/Skip.cpp
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#include <Commands/BumbleBeeCommand.hpp>
|
||||||
|
|
||||||
|
namespace bumbleBee::commands {
|
||||||
|
void Skip::execute(const dpp::slashcommand_t &event) {
|
||||||
|
event.edit_original_response(dpp::message("skip"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Skip::init() {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,45 +1,44 @@
|
|||||||
#include <MusicQueue.hpp>
|
#include <Queue/MusicQueue.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
namespace bumbleBee {
|
namespace bumbleBee {
|
||||||
|
|
||||||
void MusicQueue::enqueue(std::shared_ptr<MusicQueueElement> Element) {
|
void MusicQueue::enqueue(std::shared_ptr<MusicQueueElement> Element) {
|
||||||
std::lock_guard<std::mutex> lock(queueMutex);
|
std::lock_guard<std::mutex> lock(queueMutex);
|
||||||
queue.push_back(Element);
|
queue.push_back(Element);
|
||||||
|
if (queue.size() == 1) // 이전에 하나도 없었다는 말이므로.
|
||||||
|
currentPlayingPosition = queue.begin(); // 첫번째 곡으로 iterator를 옮겨준다.
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<MusicQueueElement> MusicQueue::dequeue() {
|
std::shared_ptr<MusicQueueElement> MusicQueue::dequeue() {
|
||||||
std::lock_guard<std::mutex> lock(queueMutex);
|
std::lock_guard<std::mutex> lock(queueMutex);
|
||||||
auto value = std::move(queue.front());
|
auto value = queue.front();
|
||||||
queue.pop_front();
|
queue.pop_front();
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
std::shared_ptr<MusicQueueElement> MusicQueue::findById(std::string id) {
|
std::list<std::shared_ptr<MusicQueueElement>>::iterator MusicQueue::findById(std::string id) {
|
||||||
std::lock_guard<std::mutex> lock(queueMutex);
|
std::lock_guard<std::mutex> lock(queueMutex);
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for (auto iter = queue.begin(); iter != queue.end(); iter++) {
|
for (auto iter = queue.begin(); iter != queue.end(); iter++) {
|
||||||
if ((*iter).get()->id == id)
|
if ((*iter).get()->id == id)
|
||||||
return *iter;
|
return iter;
|
||||||
}
|
}
|
||||||
return std::shared_ptr<MusicQueueElement>();
|
return queue.end();
|
||||||
}
|
}
|
||||||
std::weak_ptr<MusicQueueElement> MusicQueue::nowplaying()
|
std::shared_ptr<MusicQueueElement> MusicQueue::nowplaying() {
|
||||||
{
|
|
||||||
return *currentPlayingPosition;
|
return *currentPlayingPosition;
|
||||||
}
|
}
|
||||||
std::weak_ptr<MusicQueueElement> MusicQueue::next_music() {
|
std::list<std::shared_ptr<MusicQueueElement>>::iterator MusicQueue::next_music() {
|
||||||
std::lock_guard<std::mutex> lock(queueMutex);
|
std::lock_guard<std::mutex> lock(queueMutex);
|
||||||
if (currentPlayingPosition == queue.end())
|
if (currentPlayingPosition == std::prev(queue.end()) || !repeat)
|
||||||
return *currentPlayingPosition;
|
return queue.end();
|
||||||
|
if (currentPlayingPosition == std::prev(queue.end()) || repeat)
|
||||||
++currentPlayingPosition;
|
|
||||||
|
|
||||||
if (repeat && currentPlayingPosition == queue.end()) {
|
|
||||||
currentPlayingPosition = queue.begin();
|
currentPlayingPosition = queue.begin();
|
||||||
}
|
else
|
||||||
return *currentPlayingPosition;
|
++currentPlayingPosition;
|
||||||
|
return currentPlayingPosition;
|
||||||
}
|
}
|
||||||
std::weak_ptr<MusicQueueElement> MusicQueue::jump_to_index(int idx) {
|
std::shared_ptr<MusicQueueElement> MusicQueue::jump_to_index(int idx) {
|
||||||
std::lock_guard<std::mutex> lock(queueMutex);
|
std::lock_guard<std::mutex> lock(queueMutex);
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for (auto iter = queue.begin(); iter != queue.end(); iter++) {
|
for (auto iter = queue.begin(); iter != queue.end(); iter++) {
|
||||||
@@ -50,4 +49,4 @@ std::weak_ptr<MusicQueueElement> MusicQueue::jump_to_index(int idx) {
|
|||||||
}
|
}
|
||||||
return std::shared_ptr<MusicQueueElement>();
|
return std::shared_ptr<MusicQueueElement>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,51 +1,82 @@
|
|||||||
#include <Settings/SettingsManager.hpp>
|
#include <Settings/SettingsManager.hpp>
|
||||||
|
#include <dpp/nlohmann/json.hpp>
|
||||||
|
#include <Utils/ConsoleUtils.hpp>
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
namespace bumbleBee {
|
namespace bumbleBee {
|
||||||
|
|
||||||
std::string settingsManager::TOKEN = "";
|
std::string settingsManager::TOKEN = "";
|
||||||
std::string settingsManager::YTDLP_CMD = "./yt-dlp";
|
std::string settingsManager::YTDLP_CMD = "./yt-dlp";
|
||||||
std::string settingsManager::FFMPEG_CMD = "./ffmpeg/bin/ffmpeg";
|
std::string settingsManager::FFMPEG_CMD = "./ffmpeg/bin/ffmpeg";
|
||||||
std::string settingsManager::DBURL = "";
|
dpp::loglevel settingsManager::LOGLEVEL = dpp::ll_debug;
|
||||||
std::string settingsManager::DBUSER = "";
|
bool settingsManager::CLCOMMAND = false;
|
||||||
std::string settingsManager::DBPASSWORD = "";
|
|
||||||
|
|
||||||
void settingsManager::load() {
|
bool settingsManager::validateToken() {
|
||||||
|
nlohmann::json response;
|
||||||
|
if (ConsoleUtils::getResultFromCommand("which curl").size() == 0) {
|
||||||
|
std::cout << "curl is unavaliable. unresolable error please install curl." << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string stresult = ConsoleUtils::getResultFromCommand("curl -sX GET \"https://discord.com/api/v10/users/@me\" -H \"Authorization: Bot " +
|
||||||
|
TOKEN + "\"").front();
|
||||||
|
std::stringstream ss(stresult);
|
||||||
|
ss >> response;
|
||||||
|
|
||||||
|
if (response.contains("message") && response["message"] == "401: Unauthorized") {
|
||||||
|
std::cout << "Token is invalid" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool settingsManager::load() {
|
||||||
nlohmann::json configdocument;
|
nlohmann::json configdocument;
|
||||||
try {
|
try {
|
||||||
std::ifstream configfile("config.json");
|
std::ifstream configfile("config.json");
|
||||||
|
if (!configfile) {
|
||||||
|
saveToFile();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
configfile >> configdocument;
|
configfile >> configdocument;
|
||||||
|
|
||||||
TOKEN = configdocument["TOKEN"];
|
TOKEN = configdocument["TOKEN"];
|
||||||
|
|
||||||
|
if (!validateToken())
|
||||||
|
return false;
|
||||||
|
|
||||||
YTDLP_CMD = configdocument["YTDLP_CMD"];
|
YTDLP_CMD = configdocument["YTDLP_CMD"];
|
||||||
FFMPEG_CMD = configdocument["FFMPEG_CMD"];
|
FFMPEG_CMD = configdocument["FFMPEG_CMD"];
|
||||||
DBURL = configdocument["DBURL"];
|
|
||||||
DBUSER = configdocument["DBUSER"];
|
std::string level = configdocument["LOGLEVEL"];
|
||||||
DBPASSWORD = configdocument["DBPASSWORD"];
|
|
||||||
|
std::transform(level.begin(), level.end(), level.begin(), ::tolower);
|
||||||
|
if (level == "trace")
|
||||||
|
LOGLEVEL = dpp::ll_trace;
|
||||||
|
else if (level == "debug")
|
||||||
|
LOGLEVEL = dpp::ll_debug;
|
||||||
|
else if (level == "warning")
|
||||||
|
LOGLEVEL = dpp::ll_warning;
|
||||||
|
else if (level == "error")
|
||||||
|
LOGLEVEL = dpp::ll_error;
|
||||||
|
else if (level == "critical")
|
||||||
|
LOGLEVEL = dpp::ll_critical;
|
||||||
|
else // 값이 병신같을때 기본값으로 ll_info 부여
|
||||||
|
LOGLEVEL = dpp::ll_info;
|
||||||
|
|
||||||
|
CLCOMMAND = configdocument["CLEAR_PREVIOUS_COMMAND"];
|
||||||
}
|
}
|
||||||
catch (const nlohmann::json::type_error& e) {
|
catch (const nlohmann::json::type_error& e) {
|
||||||
saveToFile();
|
saveToFile();
|
||||||
std::ifstream configfile("config.json");
|
return load();
|
||||||
configfile >> configdocument;
|
|
||||||
|
|
||||||
TOKEN = configdocument["TOKEN"];
|
|
||||||
YTDLP_CMD = configdocument["YTDLP_CMD"];
|
|
||||||
FFMPEG_CMD = configdocument["FFMPEG_CMD"];
|
|
||||||
DBURL = configdocument["DBURL"];
|
|
||||||
DBUSER = configdocument["DBUSER"];
|
|
||||||
DBPASSWORD = configdocument["DBPASSWORD"];
|
|
||||||
}
|
}
|
||||||
catch (const nlohmann::json::parse_error& e) {
|
catch (const nlohmann::json::parse_error& e) {
|
||||||
saveToFile();
|
saveToFile();
|
||||||
std::ifstream configfile("config.json");
|
return load();
|
||||||
configfile >> configdocument;
|
|
||||||
|
|
||||||
TOKEN = configdocument["TOKEN"];
|
|
||||||
YTDLP_CMD = configdocument["YTDLP_CMD"];
|
|
||||||
FFMPEG_CMD = configdocument["FFMPEG_CMD"];
|
|
||||||
DBURL = configdocument["DBURL"];
|
|
||||||
DBUSER = configdocument["DBUSER"];
|
|
||||||
DBPASSWORD = configdocument["DBPASSWORD"];
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void settingsManager::saveToFile() {
|
void settingsManager::saveToFile() {
|
||||||
@@ -54,9 +85,29 @@ void settingsManager::saveToFile() {
|
|||||||
configdocument["TOKEN"] = TOKEN;
|
configdocument["TOKEN"] = TOKEN;
|
||||||
configdocument["YTDLP_CMD"] = YTDLP_CMD;
|
configdocument["YTDLP_CMD"] = YTDLP_CMD;
|
||||||
configdocument["FFMPEG_CMD"] = FFMPEG_CMD;
|
configdocument["FFMPEG_CMD"] = FFMPEG_CMD;
|
||||||
configdocument["DBURL"] = DBURL;
|
|
||||||
configdocument["DBUSER"] = DBUSER;
|
switch (LOGLEVEL) {
|
||||||
configdocument["DBPASSWORD"] = DBPASSWORD;
|
case dpp::ll_trace:
|
||||||
|
configdocument["LOGLEVEL"] = "trace";
|
||||||
|
break;
|
||||||
|
case dpp::ll_debug:
|
||||||
|
configdocument["LOGLEVEL"] = "debug";
|
||||||
|
break;
|
||||||
|
case dpp::ll_info:
|
||||||
|
configdocument["LOGLEVEL"] = "info";
|
||||||
|
break;
|
||||||
|
case dpp::ll_warning:
|
||||||
|
configdocument["LOGLEVEL"] = "warning";
|
||||||
|
break;
|
||||||
|
case dpp::ll_error:
|
||||||
|
configdocument["LOGLEVEL"] = "error";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
configdocument["LOGLEVEL"] = "critical";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
configdocument["CLEAR_PREVIOUS_COMMAND"] = CLCOMMAND;
|
||||||
|
|
||||||
std::ofstream configFile("config.json");
|
std::ofstream configFile("config.json");
|
||||||
if (configFile.is_open()) {
|
if (configFile.is_open()) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#include <AsyncDownloadManager.hpp>
|
#include <Utils/AsyncDownloadManager.hpp>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include "Utils/ConsoleUtils.hpp"
|
#include "Utils/ConsoleUtils.hpp"
|
||||||
#include "Settings/SettingsManager.hpp"
|
#include "Settings/SettingsManager.hpp"
|
||||||
@@ -8,7 +8,6 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace bumbleBee {
|
namespace bumbleBee {
|
||||||
|
|
||||||
void AsyncDownloadManager::enqueueAsyncDL(std::pair<std::string, dpp::message> query) {
|
void AsyncDownloadManager::enqueueAsyncDL(std::pair<std::string, dpp::message> query) {
|
||||||
std::lock_guard<std::mutex> lock(dlQueueMutex);
|
std::lock_guard<std::mutex> lock(dlQueueMutex);
|
||||||
downloadQueue.push(query);
|
downloadQueue.push(query);
|
||||||
@@ -39,7 +38,7 @@ void AsyncDownloadManager::downloadWorker() {
|
|||||||
cluster->log(dpp::ll_info, "AsyncDownloadManager: " + query + " accepted.");
|
cluster->log(dpp::ll_info, "AsyncDownloadManager: " + query + " accepted.");
|
||||||
|
|
||||||
std::queue<std::string> ids =
|
std::queue<std::string> ids =
|
||||||
ConsoleUtils::getResultFromCommand(settingsManager::YTDLP_CMD +
|
ConsoleUtils::getResultFromCommand(settingsManager::getYTDLP_CMD() +
|
||||||
" --default-search ytsearch --flat-playlist --skip-download --quiet --ignore-errors --print id " + query);
|
" --default-search ytsearch --flat-playlist --skip-download --quiet --ignore-errors --print id " + query);
|
||||||
|
|
||||||
if (ids.size() >= 2) {
|
if (ids.size() >= 2) {
|
||||||
@@ -53,18 +52,18 @@ void AsyncDownloadManager::downloadWorker() {
|
|||||||
enqueue(std::make_pair("https://youtu.be/" + ids.front(), oRes));
|
enqueue(std::make_pair("https://youtu.be/" + ids.front(), oRes));
|
||||||
ids.pop();
|
ids.pop();
|
||||||
}
|
}
|
||||||
break;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::queue<std::string> urls =
|
std::queue<std::string> urls =
|
||||||
ConsoleUtils::getResultFromCommand(settingsManager::YTDLP_CMD +
|
ConsoleUtils::getResultFromCommand(settingsManager::getYTDLP_CMD() +
|
||||||
" -f ba* --print urls https://youtu.be/" + ids.front());
|
" -f ba* --print urls https://youtu.be/" + ids.front());
|
||||||
|
|
||||||
cluster->log(dpp::ll_debug, "url: " + urls.front());
|
cluster->log(dpp::ll_debug, "url: " + urls.front());
|
||||||
|
|
||||||
FILE* stream;
|
FILE* stream;
|
||||||
|
|
||||||
musicQueue->enqueue(std::make_shared<MusicQueueElement>(oRes, ids.front(), urls.front(), stream));
|
// musicQueue->enqueue(std::make_shared<MusicQueueElement>(oRes, ids.front(), urls.front(), stream));
|
||||||
|
|
||||||
std::string downloadID = ids.front();
|
std::string downloadID = ids.front();
|
||||||
|
|
||||||
@@ -76,12 +75,10 @@ void AsyncDownloadManager::downloadWorker() {
|
|||||||
|
|
||||||
cluster->log(dpp::ll_info, "Thread id: " + tid.str() + ": " + downloadID + " accepted.");
|
cluster->log(dpp::ll_info, "Thread id: " + tid.str() + ": " + downloadID + " accepted.");
|
||||||
|
|
||||||
std::string command = std::string("./streamAndDownload.sh " + settingsManager::YTDLP_CMD + " " + downloadID + " " + settingsManager::FFMPEG_CMD);
|
std::string command = std::string("./streamOpus.sh " + settingsManager::getYTDLP_CMD() + " " + downloadID + " " + settingsManager::getFFMPEG_CMD());
|
||||||
stream = popen(command.c_str(), "r");
|
stream = popen(command.c_str(), "r");
|
||||||
pclose(stream);
|
|
||||||
stream = NULL;
|
cluster->log(dpp::ll_info, "Thread id: " + tid.str() + " Opened stream: " + downloadID);
|
||||||
|
|
||||||
cluster->log(dpp::ll_info, "Thread id: " + tid.str() + ": " + downloadID + " download complete.");
|
|
||||||
});
|
});
|
||||||
th.detach();
|
th.detach();
|
||||||
}
|
}
|
||||||
12
src/main.cpp
12
src/main.cpp
@@ -1,18 +1,8 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <BumbleBee.hpp>
|
#include <BumbleBee.hpp>
|
||||||
#include <AsyncDownloadManager.hpp>
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
bumbleBee::BumbleBee bot;
|
bumbleBee::BumbleBee bot;
|
||||||
|
bot.start();
|
||||||
bumbleBee::AsyncDownloadManager& manager = bumbleBee::AsyncDownloadManager::getInstance(5, bot.cluster, bot.queue);
|
|
||||||
manager.enqueue(std::make_pair("https://music.youtube.com/watch?v=4NnqIu_v1QA&si=buZP2UwzQtJLENmb", nullptr));
|
|
||||||
|
|
||||||
std::thread th([](){sleep(60);});
|
|
||||||
th.join();
|
|
||||||
manager.stop();
|
|
||||||
|
|
||||||
std::cout << "\n\n\n\n\nend\n\n\n\n\n\n\n";
|
|
||||||
//bot.start();
|
|
||||||
}
|
}
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
YTDLP_CMD=$1
|
|
||||||
DOWNLOAD_ID=$2
|
|
||||||
FFMPEG_CMD=$3
|
|
||||||
|
|
||||||
$YTDLP_CMD -o - --quiet --ignore-errors -f bestaudio https://youtu.be/$DOWNLOAD_ID | \
|
|
||||||
$FFMPEG_CMD -i - -hide_banner -ar 48000 -ac 2 -c:a libopus -f ogg -
|
|
||||||
12
streamOpus.sh
Executable file
12
streamOpus.sh
Executable file
@@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
YTDLP_CMD=$1
|
||||||
|
FFMPEG_CMD=$2
|
||||||
|
URL=$3
|
||||||
|
|
||||||
|
$YTDLP_CMD -o - --quiet --ignore-errors -f bestaudio $URL | \
|
||||||
|
$FFMPEG_CMD -hwaccel vaapi -i - -hide_banner -c:a copy -f opus - || \
|
||||||
|
$YTDLP_CMD -o - --quiet --ignore-errors -f bestaudio $URL | \
|
||||||
|
$FFMPEG_CMD -hwaccel vaapi -i - -hide_banner -f opus -c:a libopus -b:a 128k -ar 48000 -ac 2 -
|
||||||
|
|
||||||
|
# -loglevel quiet
|
||||||
Reference in New Issue
Block a user