일단은 임시저장, 스트리밍의 실마리를 잡았다

This commit is contained in:
2025-01-30 22:57:01 +09:00
parent 3186561818
commit c2cb16c6d7
19 changed files with 368 additions and 81 deletions

View File

@@ -1,36 +1,20 @@
#include <AsyncDownloadManager.hpp>
#include <sstream>
#include "Utils/ConsoleUtils.hpp"
#include "Settings/SettingsManager.hpp"
#include <ogg/ogg.h>
#include <oggz/oggz.h>
#include <opus/opusfile.h>
#include <memory>
namespace bumbleBee {
void AsyncDownloadManager::enqueueAsyncDL(std::string query) {
void AsyncDownloadManager::enqueueAsyncDL(std::pair<std::string, dpp::message> query) {
std::lock_guard<std::mutex> lock(dlQueueMutex);
downloadQueue.push(query);
dlQueueCondition.notify_one();
}
std::queue<std::string> getResultFromCommand(std::string cmd) {
std::string result, token;
std::queue<std::string> tokens;
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);
}
std::stringstream ss(result);
while (std::getline(ss, token, '\n')) {
tokens.push(token);
}
return tokens;
}
void AsyncDownloadManager::downloadWorker() {
std::ostringstream tid;
tid << std::this_thread::get_id();
@@ -38,38 +22,49 @@ void AsyncDownloadManager::downloadWorker() {
//mutex lock
std::unique_lock<std::mutex> dlQueueLock(dlQueueMutex);
dlQueueCondition.wait(dlQueueLock, [&]{ return !downloadQueue.empty() || terminate; });
auto cluster = bot.lock();
assert(cluster);
if (terminate) {
cluster->log(dpp::ll_info, "Terminating Thread" + tid.str());
auto cluster = weak_cluster.lock();
if (weak_cluster.expired()) {
cluster->log(dpp::ll_error, "Missing cluster, terminating thread " + tid.str());
break;
}
std::string query = downloadQueue.front();
if (terminate) {
cluster->log(dpp::ll_info, "Terminating thread " + tid.str());
break;
}
std::string query = downloadQueue.front().first;
dpp::message oRes = downloadQueue.front().second;
downloadQueue.pop();
dlQueueLock.unlock();
cluster->log(dpp::ll_info, "Enqueuing " + query + " accepted.");
cluster->log(dpp::ll_info, "AsyncDownloadManager: " + query + " accepted.");
std::queue<std::string> ids = getResultFromCommand("./yt-dlp --default-search ytsearch --flat-playlist --skip-download --quiet --ignore-errors --print id " + query);
std::queue<std::string> ids =
ConsoleUtils::getResultFromCommand(settingsManager::YTDLP_CMD +
" --default-search ytsearch --flat-playlist --skip-download --quiet --ignore-errors --print id " + query);
if (ids.size() >= 2) {
cluster->log(dpp::ll_info, query + " is playlist");
while (!ids.empty()) {
if (ids.front() == "") {
ids.pop();
continue;
}
cluster->log(dpp::ll_info, "Enqueuing " + ids.front());
enqueue("https://youtu.be/" + ids.front());
cluster->log(dpp::ll_info, "Enqueuing playlist element " + ids.front());
enqueue(std::make_pair("https://youtu.be/" + ids.front(), oRes));
ids.pop();
}
break;
}
std::queue<std::string> urls = getResultFromCommand("./yt-dlp -f ba* --print urls https://youtu.be/" + ids.front());
std::queue<std::string> urls =
ConsoleUtils::getResultFromCommand(settingsManager::YTDLP_CMD +
" -f ba* --print urls https://youtu.be/" + ids.front());
cluster->log(dpp::ll_info, "url: " + urls.front());
cluster->log(dpp::ll_debug, "url: " + urls.front());
musicQueue->enqueue(std::make_shared<MusicQueueElement>(ids.front(), urls.front()));
FILE* stream;
musicQueue->enqueue(std::make_shared<MusicQueueElement>(oRes, ids.front(), urls.front(), stream));
std::string downloadID = ids.front();
@@ -81,13 +76,12 @@ void AsyncDownloadManager::downloadWorker() {
cluster->log(dpp::ll_info, "Thread id: " + tid.str() + ": " + downloadID + " accepted.");
system(("./yt-dlp -o \"Temp/%(id)s\" --quiet --ignore-errors -f ba* https://youtu.be/" + downloadID).c_str());
std::string command = std::string("./streamAndDownload.sh " + settingsManager::YTDLP_CMD + " " + downloadID + " " + settingsManager::FFMPEG_CMD);
stream = popen(command.c_str(), "r");
pclose(stream);
stream = NULL;
system((std::string() + "yes n 2>/dev/null | ffmpeg -hide_banner -loglevel error -i \""
+ "Temp/" + downloadID + "\" -acodec libopus -vn Music/" + downloadID + ".ogg").c_str());
system((std::string() + "rm -f Temp/" + downloadID).c_str());
cluster->log(dpp::ll_info, "Thread id: " + tid.str() + ": " + downloadID + " downloaded.");
cluster->log(dpp::ll_info, "Thread id: " + tid.str() + ": " + downloadID + " download complete.");
});
th.detach();
}

View File

@@ -1,13 +1,17 @@
#include <BumbleBee.hpp>
#include <memory>
#include <Settings/SettingsManager.hpp>
#include <Utils/VersionsCheckUtils.hpp>
namespace bumbleBee{
BumbleBee::BumbleBee(nlohmann::json settings) {
this->cluster = std::make_shared<dpp::cluster>(settings["token"]);
BumbleBee::BumbleBee() {
settingsManager::load();
this->cluster = std::make_shared<dpp::cluster>(settingsManager::TOKEN);
dbDriver = sql::mariadb::get_driver_instance();
this->dbURL = std::make_shared<sql::SQLString>(settings["dbURL"]);
this->dbURL = std::make_shared<sql::SQLString>(settingsManager::DBURL);
sql::Properties pro({
{"user", std::string(settings["user"])},
{"password", std::string(settings["password"])}
{"user", std::string(settingsManager::DBUSER)},
{"password", std::string(settingsManager::DBPASSWORD)}
});
this->dbProperties = std::make_shared<sql::Properties>(pro);
@@ -16,6 +20,9 @@ BumbleBee::BumbleBee(nlohmann::json settings) {
cluster->on_ready([this](const dpp::ready_t &event){on_ready(event);});
queue = std::make_shared<MusicQueue>();
VersionsCheckUtils::validateYTDLPFFMPEGBinary(cluster);
VersionsCheckUtils::updateytdlp(cluster);
}
void BumbleBee::start() { this->cluster->start(dpp::st_wait); }

View File

@@ -14,7 +14,17 @@ std::shared_ptr<MusicQueueElement> MusicQueue::dequeue() {
queue.pop_front();
return value;
}
std::weak_ptr<MusicQueueElement> MusicQueue::nowplaying() {
std::shared_ptr<MusicQueueElement> MusicQueue::findById(std::string id) {
std::lock_guard<std::mutex> lock(queueMutex);
int index = 0;
for (auto iter = queue.begin(); iter != queue.end(); iter++) {
if ((*iter).get()->id == id)
return *iter;
}
return std::shared_ptr<MusicQueueElement>();
}
std::weak_ptr<MusicQueueElement> MusicQueue::nowplaying()
{
return *currentPlayingPosition;
}
std::weak_ptr<MusicQueueElement> MusicQueue::next_music() {
@@ -38,7 +48,6 @@ std::weak_ptr<MusicQueueElement> MusicQueue::jump_to_index(int idx) {
return *iter;
}
}
std::shared_ptr<MusicQueueElement> empty;
return empty;
return std::shared_ptr<MusicQueueElement>();
}
}

View File

@@ -0,0 +1,67 @@
#include <Settings/SettingsManager.hpp>
namespace bumbleBee {
std::string settingsManager::TOKEN = "";
std::string settingsManager::YTDLP_CMD = "./yt-dlp";
std::string settingsManager::FFMPEG_CMD = "./ffmpeg/bin/ffmpeg";
std::string settingsManager::DBURL = "";
std::string settingsManager::DBUSER = "";
std::string settingsManager::DBPASSWORD = "";
void settingsManager::load() {
nlohmann::json configdocument;
try {
std::ifstream configfile("config.json");
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::type_error& e) {
saveToFile();
std::ifstream configfile("config.json");
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) {
saveToFile();
std::ifstream configfile("config.json");
configfile >> configdocument;
TOKEN = configdocument["TOKEN"];
YTDLP_CMD = configdocument["YTDLP_CMD"];
FFMPEG_CMD = configdocument["FFMPEG_CMD"];
DBURL = configdocument["DBURL"];
DBUSER = configdocument["DBUSER"];
DBPASSWORD = configdocument["DBPASSWORD"];
}
}
void settingsManager::saveToFile() {
nlohmann::json configdocument;
configdocument["TOKEN"] = TOKEN;
configdocument["YTDLP_CMD"] = YTDLP_CMD;
configdocument["FFMPEG_CMD"] = FFMPEG_CMD;
configdocument["DBURL"] = DBURL;
configdocument["DBUSER"] = DBUSER;
configdocument["DBPASSWORD"] = DBPASSWORD;
std::ofstream configFile("config.json");
if (configFile.is_open()) {
configFile << configdocument.dump(4);
configFile.close();
}
}
}

View File

@@ -4,17 +4,14 @@
#include <thread>
int main() {
nlohmann::json configdocument;
std::ifstream configfile("config.json");
configfile >> configdocument;
bumbleBee::BumbleBee bot(configdocument);
bumbleBee::BumbleBee bot;
bumbleBee::AsyncDownloadManager& manager = bumbleBee::AsyncDownloadManager::getInstance(5, bot.cluster, bot.queue);
manager.enqueue("https://music.youtube.com/playlist?list=PL5NSTAfQ-wQBqZYMTqxADemyUW8mxJq2h&si=vFV4jlm70kxGfKNa");
manager.enqueue(std::make_pair("https://music.youtube.com/watch?v=4NnqIu_v1QA&si=buZP2UwzQtJLENmb", nullptr));
std::thread th([](){sleep(11);});
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();