mirror of
https://github.com/HappyTanuki/BumbleCee.git
synced 2025-10-25 17:35:58 +00:00
비동기 다운로드 구현 완료
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,8 +1,5 @@
|
||||
build/*
|
||||
out/
|
||||
.vs/
|
||||
.idea/
|
||||
tmp/
|
||||
Temp/
|
||||
config.json
|
||||
Music
|
||||
*.info.json
|
||||
|
||||
3
.vscode/c_cpp_properties.json
vendored
3
.vscode/c_cpp_properties.json
vendored
@@ -3,8 +3,7 @@
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**",
|
||||
"${workspaceFolder}/include"
|
||||
"${workspaceFolder}/**"
|
||||
],
|
||||
"defines": [
|
||||
"DDPP_CORO=on"
|
||||
|
||||
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
@@ -5,7 +5,7 @@
|
||||
"name": "Debug",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "/home/happytanuki/BumbleCee/build/BumbleCee",
|
||||
"program": "${workspaceFolder}/build/BumbleCee",
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}",
|
||||
"environment": [],
|
||||
|
||||
125
.vscode/settings.json
vendored
125
.vscode/settings.json
vendored
@@ -1,84 +1,81 @@
|
||||
{
|
||||
"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",
|
||||
"iosfwd": "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",
|
||||
"cctype": "cpp",
|
||||
"charconv": "cpp",
|
||||
"clocale": "cpp",
|
||||
"cmath": "cpp",
|
||||
"concepts": "cpp",
|
||||
"coroutine": "cpp",
|
||||
"csignal": "cpp",
|
||||
"cstdarg": "cpp",
|
||||
"cstddef": "cpp",
|
||||
"cstdint": "cpp",
|
||||
"cstdio": "cpp",
|
||||
"cstdlib": "cpp",
|
||||
"cstring": "cpp",
|
||||
"ctime": "cpp",
|
||||
"cwchar": "cpp",
|
||||
"cwctype": "cpp",
|
||||
"map": "cpp",
|
||||
"algorithm": "cpp",
|
||||
"numeric": "cpp",
|
||||
"ratio": "cpp",
|
||||
"utility": "cpp",
|
||||
"iomanip": "cpp",
|
||||
"iosfwd": "cpp",
|
||||
"limits": "cpp",
|
||||
"numbers": "cpp",
|
||||
"cinttypes": "cpp",
|
||||
"bitset": "cpp",
|
||||
"set": "cpp",
|
||||
"regex": "cpp",
|
||||
"format": "cpp",
|
||||
"span": "cpp",
|
||||
"any": "cpp",
|
||||
"array": "cpp",
|
||||
"atomic": "cpp",
|
||||
"strstream": "cpp",
|
||||
"bit": "cpp",
|
||||
"*.tcc": "cpp",
|
||||
"bitset": "cpp",
|
||||
"charconv": "cpp",
|
||||
"chrono": "cpp",
|
||||
"codecvt": "cpp",
|
||||
"compare": "cpp",
|
||||
"complex": "cpp",
|
||||
"concepts": "cpp",
|
||||
"condition_variable": "cpp",
|
||||
"coroutine": "cpp",
|
||||
"cstdint": "cpp",
|
||||
"deque": "cpp",
|
||||
"forward_list": "cpp",
|
||||
"list": "cpp",
|
||||
"map": "cpp",
|
||||
"set": "cpp",
|
||||
"string": "cpp",
|
||||
"unordered_map": "cpp",
|
||||
"vector": "cpp",
|
||||
"exception": "cpp",
|
||||
"algorithm": "cpp",
|
||||
"functional": "cpp",
|
||||
"iterator": "cpp",
|
||||
"memory": "cpp",
|
||||
"memory_resource": "cpp",
|
||||
"numeric": "cpp",
|
||||
"optional": "cpp",
|
||||
"random": "cpp",
|
||||
"ratio": "cpp",
|
||||
"source_location": "cpp",
|
||||
"typeindex": "cpp"
|
||||
"string_view": "cpp",
|
||||
"system_error": "cpp",
|
||||
"tuple": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"utility": "cpp",
|
||||
"fstream": "cpp",
|
||||
"future": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"iomanip": "cpp",
|
||||
"iostream": "cpp",
|
||||
"istream": "cpp",
|
||||
"limits": "cpp",
|
||||
"mutex": "cpp",
|
||||
"new": "cpp",
|
||||
"numbers": "cpp",
|
||||
"ostream": "cpp",
|
||||
"ranges": "cpp",
|
||||
"semaphore": "cpp",
|
||||
"shared_mutex": "cpp",
|
||||
"stdexcept": "cpp",
|
||||
"stop_token": "cpp",
|
||||
"streambuf": "cpp",
|
||||
"thread": "cpp",
|
||||
"cinttypes": "cpp",
|
||||
"typeindex": "cpp",
|
||||
"typeinfo": "cpp",
|
||||
"valarray": "cpp",
|
||||
"variant": "cpp"
|
||||
}
|
||||
}
|
||||
4
.vscode/tasks.json
vendored
4
.vscode/tasks.json
vendored
@@ -8,7 +8,7 @@
|
||||
"command": "make",
|
||||
"args": [],
|
||||
"options": {
|
||||
"cwd": "/home/happytanuki/BumbleCee/build/"
|
||||
"cwd": "${workspaceFolder}/build/"
|
||||
},
|
||||
"group": {
|
||||
"kind": "build",
|
||||
@@ -24,7 +24,7 @@
|
||||
".."
|
||||
],
|
||||
"options": {
|
||||
"cwd": "/home/happytanuki/BumbleCee/build/"
|
||||
"cwd": "${workspaceFolder}/build/"
|
||||
},
|
||||
"group": {
|
||||
"kind": "build",
|
||||
|
||||
@@ -78,4 +78,6 @@ else()
|
||||
endif()
|
||||
|
||||
target_link_libraries(${BOT_NAME} dpp)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_FLAGS "-g")
|
||||
@@ -6,27 +6,40 @@
|
||||
#include <thread>
|
||||
#include <condition_variable>
|
||||
#include <curl/curl.h>
|
||||
#include <dpp/dpp.h>
|
||||
#include <MusicQueue.hpp>
|
||||
|
||||
#define WORKER_COUNT 5
|
||||
|
||||
namespace bumbleBee {
|
||||
class AsyncDownloadManager {
|
||||
public:
|
||||
static void enqueue(std::string query) {
|
||||
static AsyncDownloadManager dl;
|
||||
std::thread th(&bumbleBee::AsyncDownloadManager::enqueueAsyncDL, &dl, query);
|
||||
static AsyncDownloadManager& getInstance(int worker_count, std::weak_ptr<dpp::cluster> bot, std::weak_ptr<bumbleBee::MusicQueue> musicQueue) {
|
||||
static AsyncDownloadManager dl(worker_count);
|
||||
dl.bot = bot;
|
||||
dl.musicQueue = musicQueue;
|
||||
return dl;
|
||||
}
|
||||
void enqueue(std::string query) {
|
||||
std::thread th(&bumbleBee::AsyncDownloadManager::enqueueAsyncDL, this, query);
|
||||
th.detach();
|
||||
}
|
||||
private:
|
||||
AsyncDownloadManager(){
|
||||
for (int i=0; i<WORKER_COUNT; i++) {
|
||||
std::thread th(&bumbleBee::AsyncDownloadManager::downloadWorker, &(*this));
|
||||
th.detach();
|
||||
AsyncDownloadManager(int worker_count){
|
||||
worker_thread.reserve(worker_count);
|
||||
terminate = false;
|
||||
for (int i=0; i<worker_count; i++) {
|
||||
worker_thread.emplace_back([this](){this->downloadWorker();});
|
||||
}
|
||||
}
|
||||
~AsyncDownloadManager(){
|
||||
terminate = true;
|
||||
dlQueueCondition.notify_all();
|
||||
|
||||
for (auto& t : worker_thread) {
|
||||
t.join();
|
||||
}
|
||||
}
|
||||
~AsyncDownloadManager(){}
|
||||
AsyncDownloadManager(const AsyncDownloadManager& ref) = delete;
|
||||
AsyncDownloadManager& operator=(const AsyncDownloadManager& ref) = delete;
|
||||
|
||||
void enqueueAsyncDL(std::string query);
|
||||
void downloadWorker();
|
||||
@@ -34,6 +47,10 @@ private:
|
||||
std::queue<std::string> downloadQueue;
|
||||
std::condition_variable dlQueueCondition;
|
||||
std::mutex dlQueueMutex;
|
||||
std::weak_ptr<dpp::cluster> bot;
|
||||
std::weak_ptr<bumbleBee::MusicQueue> musicQueue;
|
||||
std::vector<std::thread> worker_thread;
|
||||
bool terminate;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -27,19 +27,13 @@ public:
|
||||
* @brief 파괴자
|
||||
* @details BumbleBee의 모든 Property를 책임지고 파괴합니다
|
||||
**/
|
||||
~BumbleBee();
|
||||
~BumbleBee() {}
|
||||
|
||||
/**
|
||||
* @fn void start()
|
||||
* @brief 봇 시작
|
||||
**/
|
||||
void start();
|
||||
/**
|
||||
* @fn bool addCommand(commands::ICommand cmd)
|
||||
* @brief ICommand 인터페이스에 맞는 커맨드를 추가
|
||||
* @warning 이 메소드는 start()메소드가 호출되기 전에 호출되어야 함
|
||||
**/
|
||||
bool addCommand(commands::ICommand cmd);
|
||||
|
||||
/**
|
||||
* @fn void on_slashcommand(const dpp::slashcommand_t& event)
|
||||
@@ -53,9 +47,12 @@ public:
|
||||
* @param event
|
||||
**/
|
||||
void on_ready(const dpp::ready_t &event);
|
||||
private:
|
||||
|
||||
/// @brief DPP 기본 클러스터 객체
|
||||
std::unique_ptr<dpp::cluster> cluster;
|
||||
std::shared_ptr<dpp::cluster> cluster;
|
||||
/// @brief 음악 큐
|
||||
std::shared_ptr<MusicQueue> queue;
|
||||
private:
|
||||
/// @brief db 드라이버
|
||||
sql::Driver* dbDriver;
|
||||
/// @brief db 접속 URL
|
||||
@@ -63,9 +60,7 @@ private:
|
||||
/// @brief db 접속 속성
|
||||
std::shared_ptr<sql::Properties> dbProperties;
|
||||
/// @brief Command 목록
|
||||
std::vector<commands::ICommand> commands;
|
||||
/// @brief 음악 큐
|
||||
std::shared_ptr<MusicQueue> queue;
|
||||
std::vector<std::shared_ptr<commands::ICommand>> commands;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
@@ -1,25 +1,69 @@
|
||||
#include <AsyncDownloadManager.hpp>
|
||||
#include <sstream>
|
||||
|
||||
namespace bumbleBee {
|
||||
|
||||
void AsyncDownloadManager::enqueueAsyncDL(std::string query) {
|
||||
dlQueueMutex.lock();
|
||||
std::lock_guard<std::mutex> lock(dlQueueMutex);
|
||||
downloadQueue.push(query);
|
||||
dlQueueMutex.unlock();
|
||||
dlQueueCondition.notify_one();
|
||||
}
|
||||
|
||||
std::string getResultFromCommand(std::string cmd) {
|
||||
std::string result;
|
||||
FILE* stream;
|
||||
const int maxBuffer = 12; // 버퍼의 크기는 적당하게
|
||||
char buffer[maxBuffer];
|
||||
cmd.append(" 2>&1"); // 표준에러를 표준출력으로 redirect
|
||||
|
||||
stream = popen(cmd.c_str(), "r"); // 주어진 command를 shell로 실행하고 파이프 연결 (fd 반환)
|
||||
if (stream) {
|
||||
while (fgets(buffer, maxBuffer, stream) != NULL) result.append(buffer); // fgets: fd (stream)를 길이 (maxBuffer)만큼 읽어 버퍼 (buffer)에 저장
|
||||
pclose(stream); // 파이프 닫는 것 잊지 마시고요!
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void AsyncDownloadManager::downloadWorker() {
|
||||
std::unique_lock<std::mutex> dlQueueLock(dlQueueMutex);
|
||||
std::ostringstream tid;
|
||||
tid << std::this_thread::get_id();
|
||||
while (true) {
|
||||
//mutex lock
|
||||
dlQueueLock.lock();
|
||||
dlQueueCondition.wait(dlQueueLock, [&]{ return !downloadQueue.empty(); });
|
||||
|
||||
system(("./yt-dlp --no-clean-info-json --write-info-json --default-search ytsearch \
|
||||
--flat-playlist --skip-download --quiet --ignore-errors -f ba* " + downloadQueue.front()).c_str());
|
||||
std::unique_lock<std::mutex> dlQueueLock(dlQueueMutex);
|
||||
dlQueueCondition.wait(dlQueueLock, [&]{ return !downloadQueue.empty() || terminate; });
|
||||
std::string query = downloadQueue.front();
|
||||
downloadQueue.pop();
|
||||
dlQueueLock.unlock();
|
||||
auto cluster = bot.lock();
|
||||
assert(cluster);
|
||||
|
||||
cluster->log(dpp::ll_info, "Enqueuing " + query + " accepted.");
|
||||
|
||||
std::string idstring = getResultFromCommand("./yt-dlp --default-search ytsearch --flat-playlist --skip-download --quiet --ignore-errors --print id " + query);
|
||||
std::queue<std::string> ids;
|
||||
std::stringstream ss(idstring);
|
||||
|
||||
std::string _id;
|
||||
while (std::getline(ss, _id, '\n')) {
|
||||
ids.push(_id);
|
||||
}
|
||||
|
||||
if (ids.size() >= 2) {
|
||||
cluster->log(dpp::ll_info, "Playlist detected.");
|
||||
while (!ids.empty()) {
|
||||
cluster->log(dpp::ll_info, "Enqueuing " + ids.front());
|
||||
enqueue("https://youtu.be/" + ids.front());
|
||||
ids.pop();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
cluster->log(dpp::ll_info, "Thread id: " + tid.str() + ": " + ids.front() + " accepted.");
|
||||
|
||||
system(("./yt-dlp -o \"Temp/%(id)s\" --no-clean-info-json --write-info-json --default-search ytsearch \
|
||||
--flat-playlist --skip-download --quiet --ignore-errors -f ba* https://youtu.be/" + ids.front()).c_str());
|
||||
|
||||
cluster->log(dpp::ll_info, "Thread id: " + tid.str() + ": " + ids.front() + " downloaded.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace bumbleBee{
|
||||
BumbleBee::BumbleBee(nlohmann::json settings) {
|
||||
this->cluster = std::make_unique<dpp::cluster>(settings["token"]);
|
||||
this->cluster = std::make_shared<dpp::cluster>(settings["token"]);
|
||||
dbDriver = sql::mariadb::get_driver_instance();
|
||||
this->dbURL = std::make_shared<sql::SQLString>(settings["dbURL"]);
|
||||
sql::Properties pro({
|
||||
@@ -16,21 +16,16 @@ BumbleBee::BumbleBee(nlohmann::json settings) {
|
||||
cluster->on_ready([this](const dpp::ready_t &event){on_ready(event);});
|
||||
}
|
||||
|
||||
BumbleBee::~BumbleBee() {
|
||||
}
|
||||
|
||||
void BumbleBee::start() { this->cluster->start(dpp::st_wait); }
|
||||
|
||||
bool BumbleBee::addCommand(commands::ICommand cmd) {
|
||||
commands.push_back(cmd);
|
||||
return false;
|
||||
}
|
||||
|
||||
void BumbleBee::on_slashcommand(const dpp::slashcommand_t &event) {
|
||||
|
||||
for (auto command : commands)
|
||||
for (auto alias : command->nameAndAliases)
|
||||
if (event.command.get_command_name() == alias.name)
|
||||
(*command)(event);
|
||||
}
|
||||
|
||||
void BumbleBee::on_ready(const dpp::ready_t &event) {
|
||||
cluster->log(dpp::loglevel::ll_info, "Bot ready.");
|
||||
}
|
||||
|
||||
}
|
||||
10
src/main.cpp
10
src/main.cpp
@@ -1,5 +1,7 @@
|
||||
#include <iostream>
|
||||
#include <BumbleBee.hpp>
|
||||
#include <AsyncDownloadManager.hpp>
|
||||
#include <thread>
|
||||
|
||||
int main() {
|
||||
nlohmann::json configdocument;
|
||||
@@ -8,5 +10,11 @@ int main() {
|
||||
|
||||
bumbleBee::BumbleBee bot(configdocument);
|
||||
|
||||
bot.start();
|
||||
bumbleBee::AsyncDownloadManager& manager = bumbleBee::AsyncDownloadManager::getInstance(5, bot.cluster, bot.queue);
|
||||
manager.enqueue("https://music.youtube.com/playlist?list=PL5NSTAfQ-wQBqZYMTqxADemyUW8mxJq2h&si=S1OwPaaif_litCqN");
|
||||
|
||||
std::thread th([](){sleep(100);});
|
||||
th.join();
|
||||
|
||||
//bot.start();
|
||||
}
|
||||
Reference in New Issue
Block a user