mirror of
https://github.com/HappyTanuki/BumbleCee.git
synced 2025-10-26 09:55:14 +00:00
ytdlp 자동 다운로드 및 업데이트 로직 구현
This commit is contained in:
@@ -1,67 +0,0 @@
|
||||
#pragma once
|
||||
#include <dpp/dpp.h>
|
||||
#include <Queue/MusicQueue.hpp>
|
||||
#include <condition_variable>
|
||||
|
||||
namespace bumbleBee {
|
||||
class MusicPlayManager {
|
||||
public:
|
||||
MusicPlayManager(std::shared_ptr<dpp::cluster> cluster, std::vector<dpp::snowflake> GIDs) :
|
||||
cluster(cluster), GIDs(GIDs) {
|
||||
queueMap = std::unordered_map<dpp::snowflake, std::shared_ptr<MusicQueue>>();
|
||||
queueEmptyMutex = std::unordered_map<dpp::snowflake, std::shared_ptr<std::mutex>>();
|
||||
|
||||
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);});
|
||||
|
||||
for (auto GID : GIDs) {
|
||||
queueMap[GID] = std::make_shared<MusicQueue>();
|
||||
queueEmptyMutex[GID] = std::make_shared<std::mutex>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 play(dpp::discord_voice_client* client);
|
||||
|
||||
void queue_music(const dpp::snowflake guildId, const std::shared_ptr<MusicQueueElement> music);
|
||||
|
||||
void clear(const dpp::snowflake guildId);
|
||||
std::shared_ptr<MusicQueueElement> remove(const dpp::snowflake guildId, dpp::discord_voice_client* client, int index);
|
||||
int size(const dpp::snowflake guildId);
|
||||
|
||||
void setRepeat(const dpp::snowflake guildId, const bool value);
|
||||
bool getRepeat(const dpp::snowflake guildId);
|
||||
|
||||
std::pair<std::shared_ptr<std::list<std::shared_ptr<MusicQueueElement>>>, std::list<std::shared_ptr<MusicQueueElement>>::iterator> getQueue(const dpp::snowflake guildId);
|
||||
MusicQueueElement getNowPlaying(const dpp::snowflake guildId);
|
||||
|
||||
std::condition_variable queuedCondition;
|
||||
|
||||
private:
|
||||
std::shared_ptr<dpp::cluster> cluster;
|
||||
|
||||
std::vector<dpp::snowflake> GIDs;
|
||||
/// @brief 음악 큐
|
||||
std::unordered_map<dpp::snowflake, std::shared_ptr<MusicQueue>> queueMap;
|
||||
|
||||
std::unordered_map<dpp::snowflake, std::shared_ptr<std::mutex>> queueEmptyMutex;
|
||||
|
||||
void send_audio_to_voice(std::shared_ptr<bumbleBee::MusicQueueElement> music, dpp::discord_voice_client* client);
|
||||
};
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include <dpp/dpp.h>
|
||||
#include <Queue/MusicQueueElement.hpp>
|
||||
#include "Utils/ThreadPool.hpp"
|
||||
|
||||
namespace bumbleBee {
|
||||
class ThreadManager : public ThreadPool<dpp::snowflake, int, int> {
|
||||
public:
|
||||
bool addMusic(std::shared_ptr<bumbleBee::MusicQueueElement> music, dpp::discord_voice_client* client);
|
||||
void stopSending(dpp::snowflake gid);
|
||||
private:
|
||||
// GID, 쓰레드
|
||||
std::unordered_map<dpp::snowflake, std::thread> threadPool;
|
||||
// GID, 쓰레드 종료
|
||||
std::unordered_map<dpp::snowflake, bool> terminating;
|
||||
};
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
#pragma once
|
||||
#ifndef _BUMBLEBEE_HPP_
|
||||
#define _BUMBLEBEE_HPP_
|
||||
#include <dpp/dpp.h>
|
||||
#include <dpp/nlohmann/json.hpp>
|
||||
#include <memory>
|
||||
#include <Commands/BumbleBeeCommand.hpp>
|
||||
|
||||
namespace bumbleBee {
|
||||
/**
|
||||
* @file BumbleBee.hpp
|
||||
* @brief 메인 봇 클래스
|
||||
**/
|
||||
class BumbleBee {
|
||||
public:
|
||||
/**
|
||||
* @brief 생성자
|
||||
**/
|
||||
BumbleBee();
|
||||
/**
|
||||
* @brief 파괴자
|
||||
* @details BumbleBee의 모든 Property를 책임지고 파괴합니다
|
||||
**/
|
||||
~BumbleBee() {}
|
||||
|
||||
/**
|
||||
* @brief 봇 시작
|
||||
**/
|
||||
void start();
|
||||
|
||||
/**
|
||||
* @brief slashcommand 이벤트 인지시 콜백되는 함수
|
||||
* @param event const dpp::slashcommand_t&
|
||||
**/
|
||||
void on_slashcommand(const dpp::slashcommand_t& event);
|
||||
/**
|
||||
* @brief ready 이벤트 인지시 콜백되는 함수
|
||||
* @param event const dpp::ready_t&
|
||||
**/
|
||||
void on_ready(const dpp::ready_t& event);
|
||||
|
||||
/// @brief DPP 기본 클러스터 객체
|
||||
std::shared_ptr<dpp::cluster> cluster;
|
||||
/// @brief guild id 배열
|
||||
std::vector<dpp::snowflake> GIDs;
|
||||
|
||||
private:
|
||||
/// @brief Command 목록
|
||||
std::unordered_map<std::string, std::shared_ptr<commands::ICommand>> commands;
|
||||
/// @brief voiceclient 관련 event 처리기 <guild id, 각 길드별 MusicPlayManager 인스턴스>
|
||||
std::shared_ptr<MusicPlayManager> musicManager;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
@@ -1,69 +0,0 @@
|
||||
#pragma once
|
||||
#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(); \
|
||||
} \
|
||||
void execute(const dpp::slashcommand_t &event) override; \
|
||||
\
|
||||
protected: \
|
||||
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, "큐를 섞습니다")
|
||||
@@ -1,51 +0,0 @@
|
||||
#pragma once
|
||||
#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 = true;
|
||||
}
|
||||
void
|
||||
enqueue(std::shared_ptr<MusicQueueElement> Element);
|
||||
std::shared_ptr<MusicQueueElement>
|
||||
dequeue();
|
||||
std::list<std::shared_ptr<MusicQueueElement>>::iterator
|
||||
findById(std::string id);
|
||||
std::list<std::shared_ptr<MusicQueueElement>>::iterator
|
||||
findByIndex(int index);
|
||||
std::shared_ptr<MusicQueueElement>
|
||||
nowplaying();
|
||||
std::list<std::shared_ptr<MusicQueueElement>>::iterator
|
||||
next_music();
|
||||
std::shared_ptr<MusicQueueElement>
|
||||
jump_to_index(int idx);
|
||||
void
|
||||
clear();
|
||||
std::shared_ptr<MusicQueueElement>
|
||||
erase(std::list<std::shared_ptr<MusicQueueElement>>::iterator it);
|
||||
std::pair<std::shared_ptr<std::list<std::shared_ptr<MusicQueueElement>>>, std::list<std::shared_ptr<MusicQueueElement>>::iterator>
|
||||
getQueueCopy();
|
||||
int
|
||||
size();
|
||||
std::list<std::shared_ptr<MusicQueueElement>>::iterator
|
||||
end();
|
||||
|
||||
bool repeat;
|
||||
|
||||
std::list<std::shared_ptr<MusicQueueElement>>::iterator currentPlayingPosition;
|
||||
|
||||
private:
|
||||
std::list<std::shared_ptr<MusicQueueElement>> queue;
|
||||
std::mutex queueMutex;
|
||||
};
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
#pragma once
|
||||
#include <dpp/dpp.h>
|
||||
|
||||
namespace bumbleBee {
|
||||
|
||||
class MusicQueueElement {
|
||||
public:
|
||||
MusicQueueElement(
|
||||
std::string id,
|
||||
std::string query,
|
||||
dpp::user issuingUser,
|
||||
dpp::embed embed) :
|
||||
id(id), query(query), issuingUser(issuingUser), embed(embed) {}
|
||||
|
||||
const std::string id;
|
||||
const std::string query;
|
||||
const dpp::user issuingUser;
|
||||
const dpp::embed embed;
|
||||
};
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
#pragma once
|
||||
#include <dpp/dpp.h>
|
||||
|
||||
#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 {
|
||||
/// @brief 모든 설정은 이 객체를 통해 스태틱하게 제공됨.
|
||||
class SettingsManager {
|
||||
/// @brief 봇 토큰
|
||||
_DECLARE_DEFAULT_ACCESSER_STATIC_VARIABLE(std::string, TOKEN, TOKEN)
|
||||
/// @brief yt-dlp 실행 명령어
|
||||
_DECLARE_DEFAULT_ACCESSER_STATIC_VARIABLE(std::string, YTDLP_CMD, YTDLP_CMD)
|
||||
/// @brief ffmpeg 실행 명령어
|
||||
_DECLARE_DEFAULT_ACCESSER_STATIC_VARIABLE(std::string, FFMPEG_CMD, FFMPEG_CMD)
|
||||
/// @brief 로그레벨
|
||||
_DECLARE_DEFAULT_ACCESSER_STATIC_VARIABLE(dpp::loglevel, LOGLEVEL, LOGLEVEL)
|
||||
/// @brief 이전에 있던 명령을 지우고 등록할지 선택합니다.
|
||||
_DECLARE_DEFAULT_ACCESSER_STATIC_VARIABLE(bool, REGISTER_COMMAND, REGISTER_COMMAND)
|
||||
public:
|
||||
/// @brief 설정 로드하기, 설정은 이 load()를 부르기 전까지는 적절하지 못한 값을 가지고 있음.
|
||||
/// @return 로드 성공 시 true, 실패 시 false 반환.
|
||||
static bool load();
|
||||
/// @brief 설정 변경사항 저장
|
||||
static void saveToFile();
|
||||
/// @brief 토큰이 유효한지 체크합니다.
|
||||
/// @return 유효한 토큰이면 true, 아니면 false를 반환합니다.
|
||||
static bool validateToken();
|
||||
};
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
#pragma once
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <condition_variable>
|
||||
#include <dpp/dpp.h>
|
||||
#include <Queue/MusicQueue.hpp>
|
||||
|
||||
namespace bumbleBee {
|
||||
/// @brief 싱글톤 멀티스레딩 다운로드 매니저
|
||||
class [[deprecated]] AsyncDownloadManager {
|
||||
public:
|
||||
static AsyncDownloadManager& getInstance(int worker_count, std::weak_ptr<dpp::cluster> weak_cluster) {
|
||||
static AsyncDownloadManager dl(worker_count);
|
||||
dl.weak_cluster = weak_cluster;
|
||||
return dl;
|
||||
}
|
||||
void enqueue(std::pair<std::string, dpp::message> query) {
|
||||
std::thread th(&bumbleBee::AsyncDownloadManager::enqueueAsyncDL, this, query);
|
||||
th.detach();
|
||||
}
|
||||
void stop() {
|
||||
auto cluster = weak_cluster.lock();
|
||||
cluster->log(dpp::ll_info, "AsyncDownloadManager stop/destructor called.");
|
||||
terminate = true;
|
||||
dlQueueCondition.notify_all();
|
||||
|
||||
for (auto& t : worker_thread) {
|
||||
t.join();
|
||||
}
|
||||
}
|
||||
|
||||
~AsyncDownloadManager(){
|
||||
stop();
|
||||
}
|
||||
|
||||
private:
|
||||
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();});
|
||||
}
|
||||
}
|
||||
|
||||
void enqueueAsyncDL(std::pair<std::string, dpp::message> query);
|
||||
void downloadWorker();
|
||||
|
||||
std::queue<std::pair<std::string, dpp::message>> downloadQueue;
|
||||
std::condition_variable dlQueueCondition;
|
||||
std::mutex dlQueueMutex;
|
||||
std::weak_ptr<dpp::cluster> weak_cluster;
|
||||
std::vector<std::thread> worker_thread;
|
||||
bool terminate;
|
||||
};
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
#pragma once
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <queue>
|
||||
#include <regex>
|
||||
#include <boost/process.hpp>
|
||||
|
||||
namespace bumbleBee {
|
||||
class ConsoleUtils {
|
||||
public:
|
||||
/**
|
||||
* @brief 명령어를 쉘에서 실행하고 결과를 EOF 전까지 읽어 \n을 구분자로 토큰화하여 반환합니다
|
||||
* @param cmd 실행할 명령
|
||||
* @param args 아규먼트
|
||||
* @return std::queue<std::string> tokens
|
||||
*/
|
||||
static std::queue<std::string> safe_execute_command(const std::string& cmd, const std::vector<std::string>& args) {
|
||||
std::queue<std::string> tokens;
|
||||
try {
|
||||
boost::process::ipstream output; // 명령의 출력을 받을 스트림
|
||||
boost::process::child c(cmd, boost::process::args(args), boost::process::std_out > output);
|
||||
|
||||
std::string line;
|
||||
while (!output.eof() && std::getline(output, line))
|
||||
tokens.push(line);
|
||||
|
||||
c.wait(); // 프로세스가 종료될 때까지 대기
|
||||
return tokens;
|
||||
} catch (const std::exception& e) {
|
||||
return tokens;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief 명령어를 쉘에서 실행하고 결과를 파이프로 연결하여 반환합니다
|
||||
* @param cmd 실행할 명령
|
||||
* @param args 아규먼트
|
||||
* @return FILE* fd
|
||||
*/
|
||||
static FILE* safe_open_pipe(const std::string& cmd, const std::vector<std::string>& args) {
|
||||
boost::process::pipe pipe;
|
||||
boost::process::child c(cmd, boost::process::args(args), boost::process::std_out > pipe);
|
||||
|
||||
return fdopen(pipe.native_source(), "r");
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
#pragma once
|
||||
#include <dpp/dpp.h>
|
||||
#include <Queue/MusicQueueElement.hpp>
|
||||
#include <cmath>
|
||||
|
||||
namespace bumbleBee {
|
||||
class QueuedMusicListEmbedProvider {
|
||||
public:
|
||||
static std::queue<dpp::embed> makeEmbed(std::shared_ptr<std::list<std::shared_ptr<MusicQueueElement>>> queue, std::list<std::shared_ptr<MusicQueueElement>>::iterator np, bool repeat) {
|
||||
std::queue<dpp::embed> returnValue;
|
||||
std::list<std::shared_ptr<MusicQueueElement>>::iterator it = queue->begin();
|
||||
if (queue->size() == 0) {
|
||||
dpp::embed embed = makeEmbedPart(queue, np, repeat, it);
|
||||
returnValue.push(embed);
|
||||
return returnValue;
|
||||
}
|
||||
for (int i = 0; i < std::ceil(queue->size() / 5.0) && it != queue->end(); i++) {
|
||||
dpp::embed embed = makeEmbedPart(queue, np, repeat, it);
|
||||
returnValue.push(embed);
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
private:
|
||||
static dpp::embed makeEmbedPart(
|
||||
std::shared_ptr<std::list<std::shared_ptr<MusicQueueElement>>> queue,
|
||||
std::list<std::shared_ptr<MusicQueueElement>>::iterator np,
|
||||
bool repeat,
|
||||
std::list<std::shared_ptr<MusicQueueElement>>::iterator &startIter) {
|
||||
dpp::embed embed = dpp::embed()
|
||||
.set_color(dpp::colors::sti_blue);
|
||||
|
||||
if (queue->begin() == queue->end()) {
|
||||
embed
|
||||
.set_title("큐가 비었습니다!")
|
||||
.set_timestamp(time(0));
|
||||
|
||||
if (repeat)
|
||||
embed.add_field(":repeat:","");
|
||||
|
||||
return embed;
|
||||
}
|
||||
|
||||
int startIndex = std::distance(queue->begin(), startIter) + 1;
|
||||
int index = startIndex;
|
||||
|
||||
for (; (index < startIndex + 5) && startIter != queue->end() && index < queue->size()+1; startIter++, index++) { //iter로 순회하면 왠지 모르게 이상한 값을 읽을 때가 있음 이유는 나도 몰?루
|
||||
if (*startIter == *np)
|
||||
embed.add_field (
|
||||
"np",
|
||||
"",
|
||||
true
|
||||
);
|
||||
else
|
||||
embed.add_field (
|
||||
std::to_string(index),
|
||||
"",
|
||||
true
|
||||
);
|
||||
embed.add_field (
|
||||
(*startIter)->embed.title,
|
||||
(*startIter)->embed.description,
|
||||
true
|
||||
)
|
||||
.add_field("","");
|
||||
}
|
||||
|
||||
if (startIter == queue->end() || index >= queue->size()+1) {
|
||||
embed.set_timestamp(time(0));
|
||||
if (repeat)
|
||||
embed.add_field(":repeat:","");
|
||||
}
|
||||
|
||||
return embed;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
#pragma once
|
||||
#include <dpp/dpp.h>
|
||||
#include "ConsoleUtils.hpp"
|
||||
#include "../Settings/SettingsManager.hpp"
|
||||
|
||||
namespace bumbleBee {
|
||||
class VersionsCheckUtils {
|
||||
public:
|
||||
static bool isThereCMD(std::shared_ptr<dpp::cluster> cluster, std::string cmd) {
|
||||
if (ConsoleUtils::safe_execute_command("/usr/bin/which", {cmd}).size() == 0) {
|
||||
cluster->log(dpp::ll_error, cmd + " is unavaliable. unresolable error please install " + cmd);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
static void validateFFMPEG(std::shared_ptr<dpp::cluster> cluster) {
|
||||
std::queue<std::string> result = ConsoleUtils::safe_execute_command(SettingsManager::getFFMPEG_CMD(), {"-version"});
|
||||
std::string front = result.front();
|
||||
if (front[0] != 'f' ||
|
||||
front[1] != 'f' ||
|
||||
front[2] != 'm' ||
|
||||
front[3] != 'p' ||
|
||||
front[4] != 'e' ||
|
||||
front[5] != 'g') {
|
||||
cluster->log(dpp::ll_warning, "ffmpeg is unavailable. downloading ffmpeg...");
|
||||
|
||||
if (!isThereCMD(cluster, "curl")) {
|
||||
exit(1);
|
||||
}
|
||||
if (!isThereCMD(cluster, "tar")) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
system("curl -LO https://github.com/BtbN/FFmpeg-Builds/releases/latest/download/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("mv ffmpeg-master-latest-linux64-gpl/bin/ffmpeg .");
|
||||
system("rm -rf ffmpeg-master-latest-linux64-gpl");
|
||||
SettingsManager::setFFMPEG_CMD("./ffmpeg");
|
||||
}
|
||||
}
|
||||
|
||||
static void validateYTDLP(std::shared_ptr<dpp::cluster> cluster) {
|
||||
std::queue<std::string> result = ConsoleUtils::safe_execute_command(SettingsManager::getYTDLP_CMD(), {"--version"});
|
||||
std::string front = result.front();
|
||||
if ((front[0]-'0' < 0 || front[0]-'0' > 9) ||
|
||||
(front[1]-'0' < 0 || front[1]-'0' > 9) ||
|
||||
(front[2]-'0' < 0 || front[2]-'0' > 9) ||
|
||||
(front[3]-'0' < 0 || front[3]-'0' > 9)) {
|
||||
cluster->log(dpp::ll_warning, "ytdlp is unavailable. downloading ytdlp...");
|
||||
|
||||
if (!isThereCMD(cluster, "curl")) {
|
||||
exit(1);
|
||||
}
|
||||
if (!isThereCMD(cluster, "tar")) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
system("curl -LO https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp");
|
||||
system("chmod +x ./yt-dlp");
|
||||
SettingsManager::setYTDLP_CMD("./yt-dlp");
|
||||
}
|
||||
}
|
||||
|
||||
static void validateYTDLPFFMPEGBinary(std::shared_ptr<dpp::cluster> cluster) {
|
||||
cluster->log(dpp::ll_info, "Checking if yt-dlp and ffmpeg is available...");
|
||||
validateFFMPEG(cluster);
|
||||
validateYTDLP(cluster);
|
||||
}
|
||||
|
||||
static void updateytdlp(std::shared_ptr<dpp::cluster> cluster) {
|
||||
cluster->log(dpp::ll_info, "Checking if yt-dlp update is available...");
|
||||
std::queue<std::string> result = ConsoleUtils::safe_execute_command("./yt-dlp", {"-U"});
|
||||
while(!result.empty()) {
|
||||
std::string front = result.front();
|
||||
result.pop();
|
||||
cluster->log(dpp::ll_info, front);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
23
include/precomp.h
Normal file
23
include/precomp.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef BUMBLEBEE_INCLUDE_PRECOMP_H_
|
||||
#define BUMBLEBEE_INCLUDE_PRECOMP_H_
|
||||
#ifdef WIN32
|
||||
#include <winsock2.h>
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <queue>
|
||||
|
||||
#include "boost/asio.hpp"
|
||||
#include "boost/beast/http.hpp"
|
||||
#include "boost/beast/ssl.hpp"
|
||||
#include "boost/log/trivial.hpp"
|
||||
#include "boost/process.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "libavformat/avformat.h"
|
||||
#include "libavutil/avutil.h"
|
||||
#include "libswresample/swresample.h"
|
||||
#include "libswscale/swscale.h"
|
||||
}
|
||||
|
||||
#endif // BUMBLEBEE_INCLUDE_PRECOMP_H_
|
||||
38
include/utils/console.h
Normal file
38
include/utils/console.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifndef BUMBLEBEE_INCLUDE_UTILS_CONSOLE_H_
|
||||
#define BUMBLEBEE_INCLUDE_UTILS_CONSOLE_H_
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
namespace utils {
|
||||
// @brief 명령어가 실행 가능한지 체크합니다
|
||||
// @param cmd 실행할 명령
|
||||
// @return int error_code
|
||||
int ValidateCommand(std::string cmd);
|
||||
// @brief 명령어를 쉘에서 실행하고 결과를 EOF 전까지 읽어 반환합니다
|
||||
// @param cmd 실행할 명령
|
||||
// @param args 아규먼트
|
||||
// @return int error_code
|
||||
int ExecuteCommand(
|
||||
const std::string& cmd,
|
||||
const std::vector<std::string>& args = std::vector<std::string>());
|
||||
// @brief 명령어를 쉘에서 실행하고 결과를 EOF 전까지 읽어 반환합니다
|
||||
// @param cmd 실행할 명령
|
||||
// @param result 실행결과
|
||||
// @return int error_code
|
||||
int ExecuteCommand(const std::string& cmd, std::string& result);
|
||||
// @brief 명령어를 쉘에서 실행하고 결과를 EOF 전까지 읽어 반환합니다
|
||||
// @param cmd 실행할 명령
|
||||
// @param args 아규먼트
|
||||
// @param result 실행결과
|
||||
// @return int error_code
|
||||
int ExecuteCommand(const std::string& cmd, const std::vector<std::string>& args,
|
||||
std::string& result);
|
||||
// @brief 명령어를 쉘에서 실행하고 결과를 파이프로 연결하여 반환합니다
|
||||
// @param cmd 실행할 명령
|
||||
// @param args 아규먼트
|
||||
// @return boost::process::popen
|
||||
boost::process::popen OpenPipe(
|
||||
const std::string& cmd,
|
||||
const std::vector<std::string>& args = std::vector<std::string>());
|
||||
} // namespace utils
|
||||
#endif
|
||||
10
include/utils/file_downloader.h
Normal file
10
include/utils/file_downloader.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef BUMBLEBEE_INCLUDE_UTILS_FILE_DOWNLOADER_H_
|
||||
#define BUMBLEBEE_INCLUDE_UTILS_FILE_DOWNLOADER_H_
|
||||
#include "precomp.h"
|
||||
|
||||
namespace utils {
|
||||
|
||||
void DownloadFileFromHTTPS(std::string url, std::string filename);
|
||||
}
|
||||
|
||||
#endif
|
||||
14
include/utils/update_checker.h
Normal file
14
include/utils/update_checker.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef BUMBLEBEE_INCLUDE_UTILS_UPDATE_CHECKER_H_
|
||||
#define BUMBLEBEE_INCLUDE_UTILS_UPDATE_CHECKER_H_
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
namespace utils {
|
||||
|
||||
int InstallYtdlp();
|
||||
|
||||
int CheckUpdate();
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user