From b9ab9ac60f50c04fcf69ef082f60fb76d2bb7383 Mon Sep 17 00:00:00 2001 From: HappyTanuki Date: Wed, 14 Aug 2024 20:08:35 +0900 Subject: [PATCH] =?UTF-8?q?=EC=99=80!=20=EC=86=8C=EB=A6=AC=EA=B0=80=20?= =?UTF-8?q?=EB=82=98=EC=9A=94!=20=EA=B7=BC=EB=8D=B0=20=EB=8F=84=EB=8B=B9?= =?UTF-8?q?=EC=B2=B4=20=EC=BD=94=EB=A3=A8=ED=8B=B4=EC=9D=80=20=EC=99=9C=20?= =?UTF-8?q?=EC=95=88=20=EB=90=98=EB=8A=94=EB=8D=B0;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 2 + include/Bot.hpp | 7 +- include/BumbleCeepp.hpp | 14 +++- include/Commands/Play.hpp | 1 + src/Bot.cpp | 10 +-- src/BumbleCeepp.cpp | 124 ++++++++++++++++++--------- src/Commands/Delete.cpp | 2 +- src/Commands/Play.cpp | 172 +++++++++++++++++++++----------------- src/Commands/Queue.cpp | 4 +- src/main.cpp | 2 - youtube-search.py | 25 +++++- yt-download.py | 42 ++-------- 12 files changed, 228 insertions(+), 177 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1941045..783d9c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,11 +37,13 @@ endif() target_include_directories(${BOT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include ${OPENSSL_INCLUDE_DIR} + /usr/include/opus ) target_link_libraries(${BOT_NAME} dl dpp + opus oggz mariadbcpp ${CMAKE_THREAD_LIBS_INIT} diff --git a/include/Bot.hpp b/include/Bot.hpp index d1a3e02..a4f804d 100644 --- a/include/Bot.hpp +++ b/include/Bot.hpp @@ -6,7 +6,7 @@ class IBot { public: - IBot(std::string token, std::string DBURL, std::string DBID, std::string DBPassword, int clusterCount = 0); + IBot(std::string token, int clusterCount = 0); virtual void start(); virtual void onCommand(const dpp::slashcommand_t &event); virtual void onReady(const dpp::ready_t &event); @@ -24,9 +24,4 @@ public: }; dpp::loglevel logLevel = dpp::ll_debug; - -protected: - sql::Driver* DBDriver; - std::shared_ptr DBURL; - std::shared_ptr DBProperties; }; diff --git a/include/BumbleCeepp.hpp b/include/BumbleCeepp.hpp index 3c85a67..6e2c44b 100644 --- a/include/BumbleCeepp.hpp +++ b/include/BumbleCeepp.hpp @@ -9,10 +9,18 @@ class BumbleCeepp : public IBot { public: BumbleCeepp(std::string token, std::string DBURL, std::string DBID, std::string DBPassword, int clusterCount = 0); + ~BumbleCeepp(); void enqueueMusic(FQueueElement item, dpp::discord_voice_client* vc); - dpp::embed findEmbed(std::string musicID); - dpp::embed makeEmbed( + std::shared_ptr findEmbed(std::string musicID); + bool insertDB( + std::string webpage_url, + std::string title, + std::string uploader, + std::string id, + std::string thumbnail, + time_t duration); + std::shared_ptr makeEmbed( std::string webpage_url, std::string title, std::string uploader, @@ -26,5 +34,5 @@ public: private: // 쌍임. std::unordered_map enqueuingMutexMap; - std::unordered_map musicEmbedMap; + sql::Connection* conn; }; \ No newline at end of file diff --git a/include/Commands/Play.hpp b/include/Commands/Play.hpp index ebd1ad9..1c2ba0a 100644 --- a/include/Commands/Play.hpp +++ b/include/Commands/Play.hpp @@ -9,5 +9,6 @@ public: Play(dpp::snowflake botID, BumbleCeepp* Bot); void operator()(const dpp::slashcommand_t& event); + void on_DLCompleted(std::string musicID, dpp::embed embed, const dpp::slashcommand_t& event); }; } \ No newline at end of file diff --git a/src/Bot.cpp b/src/Bot.cpp index eec668b..d95a7f8 100644 --- a/src/Bot.cpp +++ b/src/Bot.cpp @@ -1,16 +1,8 @@ #include #include -IBot::IBot(std::string token, std::string DBURL, std::string DBID, std::string DBPassword, int clusterCount) +IBot::IBot(std::string token, int clusterCount) { - this->DBURL = std::make_shared(DBURL); - sql::Properties pro({ - {"user", DBID}, - {"password", DBPassword} - }); - this->DBProperties = std::make_shared(pro); - DBDriver = sql::mariadb::get_driver_instance(); - botCluster = std::make_shared(token, dpp::i_default_intents, clusterCount); botCluster->on_log(logger()); diff --git a/src/BumbleCeepp.cpp b/src/BumbleCeepp.cpp index 552e06d..c146e86 100644 --- a/src/BumbleCeepp.cpp +++ b/src/BumbleCeepp.cpp @@ -5,15 +5,21 @@ #include BumbleCeepp::BumbleCeepp(std::string token, std::string DBURL, std::string DBID, std::string DBPassword, int clusterCount) - : IBot(token, DBURL, DBID, DBPassword, clusterCount) + : IBot(token, clusterCount) { + sql::Properties pro({ + {"user", DBID}, + {"password", DBPassword} + }); + + conn = sql::mariadb::get_driver_instance()->connect(DBURL, pro); commandsArray.push_back(std::make_shared(botCluster->me.id, this)); - commandsArray.push_back(std::make_shared(botCluster->me.id, this)); - commandsArray.push_back(std::make_shared(botCluster->me.id, this)); - commandsArray.push_back(std::make_shared(botCluster->me.id, this)); - commandsArray.push_back(std::make_shared(botCluster->me.id, this)); - commandsArray.push_back(std::make_shared(botCluster->me.id, this)); + // commandsArray.push_back(std::make_shared(botCluster->me.id, this)); + // commandsArray.push_back(std::make_shared(botCluster->me.id, this)); + // commandsArray.push_back(std::make_shared(botCluster->me.id, this)); + // commandsArray.push_back(std::make_shared(botCluster->me.id, this)); + // commandsArray.push_back(std::make_shared(botCluster->me.id, this)); botCluster->on_voice_track_marker([&](const dpp::voice_track_marker_t &marker) { @@ -37,7 +43,7 @@ BumbleCeepp::BumbleCeepp(std::string token, std::string DBURL, std::string DBID, marker.voice_client->log(dpp::loglevel::ll_debug, "Playing " + marker.track_meta + "on channel id " + marker.voice_client->channel_id.str() + "."); int remainingSongsCount = marker.voice_client->get_tracks_remaining(); - marker.voice_client->log(dpp::loglevel::ll_trace, "Marker count : " + remainingSongsCount); + marker.voice_client->log(dpp::loglevel::ll_debug, "Marker count : " + remainingSongsCount); if (remainingSongsCount <= 1 && !marker.voice_client->is_playing()) { @@ -50,14 +56,33 @@ BumbleCeepp::BumbleCeepp(std::string token, std::string DBURL, std::string DBID, return; } - if (repeat) - enqueueMusic({nowPlayingMusic, findEmbed(nowPlayingMusic)}, marker.voice_client); + if (repeat) { + std::shared_ptr embed; + if (nowPlayingMusic == "") { + nowPlayingMusic = marker.track_meta; + } + embed = findEmbed(nowPlayingMusic); + nowPlayingMusic = marker.track_meta; + + + if (!embed) { + botCluster->log(dpp::loglevel::ll_error, std::string("알 수 없는 오류 발생!")); + return; + } + + enqueueMusic({nowPlayingMusic, *embed}, marker.voice_client); + } }); // cluster->on_voice_ready([&](const dpp::voice_ready_t& Voice){ queue->play(); }); } +BumbleCeepp::~BumbleCeepp() +{ + conn->close(); +} + void BumbleCeepp::enqueueMusic(FQueueElement item, dpp::discord_voice_client* vc) { vc->insert_marker(item.ID); @@ -111,31 +136,59 @@ void BumbleCeepp::enqueueMusic(FQueueElement item, dpp::discord_voice_client* vc vc->log(dpp::loglevel::ll_debug, "Enqueued " + item.ID + "on channel id " + vc->channel_id.str() + "."); } -dpp::embed BumbleCeepp::findEmbed(std::string musicID) +std::shared_ptr BumbleCeepp::findEmbed(std::string musicID) { - auto iter = musicEmbedMap.find(musicID); - if (iter != musicEmbedMap.end()) - return iter->second; - - std::unique_ptr conn(DBDriver->connect(*this->DBURL, *DBProperties)); - std::unique_ptr stmnt(conn->prepareStatement("SELECT embed FROM songs_info WHERE ID = ?")); - stmnt->setString(1, musicID); - std::unique_ptr res(stmnt->executeQuery()); - - dpp::embed returnValue = makeEmbed( - res->getString("webpage_url").c_str(), - res->getString("title").c_str(), - res->getString("uploader").c_str(), - musicID, - res->getString("thumbnail").c_str(), - res->getInt("duration")); + sql::ResultSet* res; + std::shared_ptr returnValue; + try { + std::unique_ptr stmnt(conn->prepareStatement("SELECT * FROM songs_info WHERE ID = ?")); + stmnt->setString(1, musicID); + res = stmnt->executeQuery(); - musicEmbedMap[musicID] = returnValue; + if (!res->next()) { + return nullptr; + } + + returnValue = makeEmbed( + res->getString("webpage_url").c_str(), + res->getString("title").c_str(), + res->getString("uploader").c_str(), + musicID, + res->getString("thumbnail").c_str(), + res->getInt("duration")); + } + catch(sql::SQLException& e){ + botCluster->log(dpp::loglevel::ll_error, std::string("SQLError: ") + e.what()); + return nullptr; + } return returnValue; } -dpp::embed BumbleCeepp::makeEmbed(std::string webpage_url, std::string title, std::string uploader, std::string id, std::string thumbnail, time_t duration) +bool BumbleCeepp::insertDB( + std::string webpage_url, std::string title, std::string uploader, std::string id, std::string thumbnail, time_t duration) +{ + try { + std::unique_ptr stmnt( + conn->prepareStatement("REPLACE INTO songs_info (ID, webpage_url, title, uploader, thumbnail, duration) VALUE (?, ?, ?, ?, ?, ?)")); + stmnt->setString(1, id); + stmnt->setString(2, webpage_url); + stmnt->setString(3, title); + stmnt->setString(4, uploader); + stmnt->setString(5, thumbnail); + stmnt->setInt(6, duration); + stmnt->executeQuery(); + + return true; + } + catch(sql::SQLException& e){ + botCluster->log(dpp::loglevel::ll_debug, std::string("SQLError: ") + e.what()); + return false; + } +} + +std::shared_ptr BumbleCeepp::makeEmbed( + std::string webpage_url, std::string title, std::string uploader, std::string id, std::string thumbnail, time_t duration) { char SongLengthStr[10]; tm t; @@ -157,16 +210,7 @@ dpp::embed BumbleCeepp::makeEmbed(std::string webpage_url, std::string title, st true ); - std::unique_ptr conn(DBDriver->connect(*this->DBURL, *DBProperties)); - std::unique_ptr stmnt( - conn->prepareStatement("REPLACE INTO songs_info (ID, webpage_url, title, uploader, thumbnail, duration) VALUE (?, ?, ?, ?, ?, ?)")); - stmnt->setString(1, id); - stmnt->setString(2, webpage_url); - stmnt->setString(3, title); - stmnt->setString(4, uploader); - stmnt->setString(5, thumbnail); - stmnt->setInt(6, duration); - stmnt->executeQuery(); + insertDB(webpage_url, title, uploader, id, thumbnail, duration); - return returnValue; -} + return std::make_shared(returnValue); +} \ No newline at end of file diff --git a/src/Commands/Delete.cpp b/src/Commands/Delete.cpp index 590fe8a..9cb1ac1 100644 --- a/src/Commands/Delete.cpp +++ b/src/Commands/Delete.cpp @@ -37,7 +37,7 @@ void commands::Delete::operator()(const dpp::slashcommand_t& event) return; } - dpp::embed embed = Bot->findEmbed(queuedSongs[index - 1]) + dpp::embed embed = (*Bot->findEmbed(queuedSongs[index - 1])) .set_timestamp(time(0)); dpp::message msg(event.command.channel_id, "다음 항목을 큐에서 삭제했습니다!:"); diff --git a/src/Commands/Play.cpp b/src/Commands/Play.cpp index b526c0a..cdb51ca 100644 --- a/src/Commands/Play.cpp +++ b/src/Commands/Play.cpp @@ -7,6 +7,21 @@ using json = nlohmann::json; +std::string getResultFromCommand(std::string cmd) { + std::string result; + FILE* stream; + const int maxBuffer = 256; // 버퍼의 크기는 적당하게 + 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; +} + commands::Play::Play(dpp::snowflake botID, BumbleCeepp* Bot) : ICommand(botID, Bot) { @@ -30,99 +45,106 @@ void commands::Play::operator()(const dpp::slashcommand_t& event) /* Attempt to connect to a voice channel, returns false if we fail to connect. */ if (!event.from->get_voice(event.command.guild_id)) { - if (!dpp::find_guild(event.command.guild_id)->connect_member_voice(event.command.get_issuing_user().id)) + dpp::guild* g = dpp::find_guild(event.command.guild_id); + bool memberIsInVoice = g->connect_member_voice(event.command.get_issuing_user().id); + if (!memberIsInVoice) { - return event.reply("노래를 재생할 음성 채팅방에 먼저 참가하고 신청해야 합니다!"); + event.reply("노래를 재생할 음성 채팅방에 먼저 참가하고 신청해야 합니다!"); + return; } } std::string Query = std::get(event.get_parameter("query")); - dpp::detail::co_await_resolve(event.co_thinking()); + event.thinking(); - event.from->log(dpp::loglevel::ll_debug, "음악 ID 쿼리"); - dpp::utility::exec("python3 youtube-search.py", {Query}, [&](const std::string& output) -> void + event.from->log(dpp::loglevel::ll_debug, "음악 ID 쿼리: " + Query); + + std::string musicIDs = getResultFromCommand(("python3 youtube-search.py \"" + Query + "\" & wait").c_str()); + + if (!musicIDs.length()) { - if (!output.length()) - { - event.from->log(dpp::loglevel::ll_debug, "검색 결과 없음"); - event.edit_response("검색 결과가 없습니다."); - } - }); - std::system(("python3 youtube-search.py \"" + Query + "\" & wait").c_str()); - - event.from->log(dpp::loglevel::ll_debug, "음악 다운로드 시작"); - std::system(("python3 yt-download.py \"" + Query + "\" & wait").c_str()); - event.from->log(dpp::loglevel::ll_debug, "음악 다운로드 완료"); - - std::ifstream infofile, idfile; - json document; - std::string ID; - std::queue RequestedMusic; - idfile.open("Temp/CurMusic"); - while (std::getline(idfile, ID)) - { - event.from->log(dpp::loglevel::ll_trace, "Red ID : " + ID); - infofile.open("Music/" + ID + ".info.json"); - infofile >> document; - infofile.close(); - - FQueueElement Data = { - ID, - Bot->makeEmbed( - document["webpage_url"], - document["title"], - document["uploader"], - document["id"], - document["thumbnail"], - int(document["duration"])) - }; - - RequestedMusic.push(Data); + event.from->log(dpp::loglevel::ll_debug, "유튜브 검색 결과 없음"); + event.edit_response("검색 결과가 없습니다."); + return; } - idfile.close(); - std::system("rm -f Temp/CurMusic"); + event.from->log(dpp::loglevel::ll_debug, "musicIDs: " + musicIDs); - dpp::voiceconn* v = event.from->get_voice(event.command.guild_id); + std::stringstream sstream(musicIDs); + std::string musicID; + while (getline(sstream, musicID, '\n')) { + event.from->log(dpp::loglevel::ll_debug, "musicID: " + musicID); + event.from->log(dpp::loglevel::ll_debug, "DB쿼리 시도.."); + std::shared_ptr embed = Bot->findEmbed(musicID); - /* If the voice channel was invalid, or there is an issue with it, then tell the user. */ - if (v && v->voiceclient && v->voiceclient->is_ready()) - { - auto _copiedQueue = RequestedMusic; - while (!_copiedQueue.empty()) - { - Bot->enqueueMusic(_copiedQueue.front(), v->voiceclient); - _copiedQueue.pop(); + if (embed == nullptr) { + event.from->log(dpp::loglevel::ll_debug, "DB쿼리 실패"); + event.from->log(dpp::loglevel::ll_debug, "다운로드 시작"); + std::system(("python3 yt-download.py \"" + musicID + "\" & wait").c_str()); + + event.from->log(dpp::loglevel::ll_debug, "musicID: " + musicID); + std::ifstream infofile; + infofile.open((std::string("Music/") + musicID + ".info.json").c_str()); + event.from->log(dpp::loglevel::ll_debug, std::string("json file name: ") + "Music/" + musicID + ".info.json"); + json document; + infofile >> document; + infofile.close(); + + embed = Bot->makeEmbed( + document["webpage_url"], + document["title"], + document["uploader"], + document["id"], + document["thumbnail"], + int(document["duration"])); + + on_DLCompleted(musicID, *embed, event); + } + else { + event.from->log(dpp::loglevel::ll_debug, "DB쿼리 완료"); + on_DLCompleted(musicID, *embed, event); } } - else - { - auto _copiedQueue = RequestedMusic; - event.from->creator->on_voice_ready([&](const dpp::voice_ready_t& Voice) - { - while (!_copiedQueue.empty()) - { - auto item = _copiedQueue.front(); - Bot->enqueueMusic(item, Voice.voice_client); - _copiedQueue.pop(); - } - }); + return; +} + +void commands::Play::on_DLCompleted(std::string musicID, dpp::embed embed, const dpp::slashcommand_t& event) +{ + static std::string raw_event; + if (raw_event != event.raw_event){ + raw_event = event.raw_event; + + dpp::message msg(event.command.channel_id, "큐에 다음 곡을 추가했습니다:"); + msg.add_embed(embed); + event.edit_response(msg); } - - dpp::message msg(event.command.channel_id, "큐에 다음 곡을 추가했습니다:"); - msg.add_embed(RequestedMusic.front().embed); - RequestedMusic.pop(); - event.edit_original_response(msg); - - while (!RequestedMusic.empty()) - { + else { dpp::message followMsg(event.command.channel_id, ""); - followMsg.add_embed(RequestedMusic.front().embed); - RequestedMusic.pop(); + dpp::embed followEmbed = dpp::embed() + .add_field( + embed.title, + embed.description, + true + ) + .add_field( + "", + "" + ); + + followMsg.add_embed(followEmbed); event.from->creator->message_create(followMsg); } - return; + auto voiceconn = event.from->get_voice(event.command.guild_id); + + if (!voiceconn || !voiceconn->voiceclient || !voiceconn->voiceclient->is_ready()) { + event.from->creator->on_voice_ready([this, musicID, embed, voiceconn](const dpp::voice_ready_t& Voice){ + this->Bot->enqueueMusic({musicID, embed}, voiceconn->voiceclient); + }); + } + else { + Bot->enqueueMusic({musicID, embed}, voiceconn->voiceclient); + } } \ No newline at end of file diff --git a/src/Commands/Queue.cpp b/src/Commands/Queue.cpp index ca49e94..f217ab0 100644 --- a/src/Commands/Queue.cpp +++ b/src/Commands/Queue.cpp @@ -33,7 +33,7 @@ void commands::Queue::operator()(const dpp::slashcommand_t& event) { } else { msg.set_content("지금 재생 중:"); - dpp::embed curMusicEmbed = Bot->findEmbed(Bot->nowPlayingMusic); + dpp::embed curMusicEmbed = *Bot->findEmbed(Bot->nowPlayingMusic); msg.add_embed(curMusicEmbed); } @@ -44,7 +44,7 @@ void commands::Queue::operator()(const dpp::slashcommand_t& event) { int j; for (j = i; j < i + 5 && j < queuedSongs.size(); j++) { - dpp::embed originalEmbed = Bot->findEmbed(queuedSongs[j]); + dpp::embed originalEmbed = *Bot->findEmbed(queuedSongs[j]); followEmbed.add_field( std::to_string(j + 1), diff --git a/src/main.cpp b/src/main.cpp index 21388dc..c72fccb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,8 +10,6 @@ int main() std::ifstream configfile("config.json"); configfile >> configdocument; - // setvbuf(stdout, NULL, _IONBF, 0); - std::shared_ptr bumbleBee = std::make_shared( configdocument["token"], configdocument["dbURL"], configdocument["user"], configdocument["password"]); diff --git a/youtube-search.py b/youtube-search.py index a167949..c5ef482 100644 --- a/youtube-search.py +++ b/youtube-search.py @@ -12,11 +12,28 @@ def uri_validator(x): except AttributeError: return False +#URL인 경우 if uri_validator(sys.argv[1]) == True: - exit() + result = urllib.parse.urlparse(sys.argv[1]) -from youtube_search import YoutubeSearch + #플레이리스트인 경우 + if result.path == '/playlist': + import re, requests -results = YoutubeSearch(sys.argv[1], max_results=10).to_dict() + response = requests.get("https://www.youtube.com/playlist?" + result.query) -print(results[0]["id"]) \ No newline at end of file + pattern = re.compile('"videoId":"(.{11})"') + + list = set(pattern.findall(response.text)) + for it in list: + print(it) + #영상인 경우 + elif result.path == '/watch': + print(result.query[2:13]) +else: + from youtube_search import YoutubeSearch + + results = YoutubeSearch(sys.argv[1], max_results=10).to_dict() + + #검색 결과가 없는 경우 확인 불가 + print(results[0]["id"]) \ No newline at end of file diff --git a/yt-download.py b/yt-download.py index ed34512..7fec308 100644 --- a/yt-download.py +++ b/yt-download.py @@ -1,47 +1,19 @@ import yt_dlp import sys import os -import json if len(sys.argv) != 2: sys.exit() ydl_opts = { 'quiet': True, - 'clean_infojson': False, - 'default_search': 'ytsearch', 'format': '251', - 'outtmpl': {'default': 'Temp/%(id)s.temp'}, - 'overwrites': False, - 'writeinfojson': True } + 'outtmpl': {'default': 'Temp/' + sys.argv[1]}, + 'writeinfojson': True +} with yt_dlp.YoutubeDL(ydl_opts) as ydl: - info = ydl.extract_info(sys.argv[1], download=False) - id = list() - with open("out", "w") as f: - f.write(json.dumps(ydl.sanitize_info(info))) - with open("Music/Archive", "r") as f: - ArchiveList = f.read().split("\n") - if "entries" in info: - if len(info["entries"]) != 0: - for entry in info["entries"]: - if entry["id"] not in ArchiveList: - ydl.download(entry["webpage_url"]) - os.system("echo " + entry["id"] + " >> Music/Archive") - os.system("yes n 2>/dev/null | ffmpeg -hide_banner -loglevel error -i \"" + "Temp/" + entry["id"] + ".temp" + "\" -c copy Music/" + entry["id"] + ".ogg") - os.system("mv Temp/" + entry["id"] + ".temp.info.json Music/" + entry["id"] + ".info.json") - id.append(entry["id"]) - else: - if info["id"] not in ArchiveList: - ydl.download(info["webpage_url"]) - os.system("echo " + info["id"] + " >> Music/Archive") - os.system("yes n 2>/dev/null | ffmpeg -hide_banner -loglevel error -i \"" + "Temp/" + info["id"] + ".temp" + "\" -c copy Music/" + info["id"] + ".ogg") - os.system("mv Temp/" + info["id"] + ".temp.info.json Music/" + info["id"] + ".info.json") - id.append(info["id"]) - - os.system("rm -f Temp/*.temp") - os.system("rm -f Temp/*.json") - - with open("Temp/CurMusic", "w") as f: - for item in id: - f.write(item + "\n") \ No newline at end of file + info = ydl.extract_info("https://www.youtube.com/watch?v=" + sys.argv[1]) + os.system("yes n 2>/dev/null | ffmpeg -hide_banner -loglevel error -i \"" + "Temp/" + sys.argv[1] + "\" -c copy Music/" + sys.argv[1] + ".ogg > /dev/null 2> /dev/null") + os.system("mv Temp/" + sys.argv[1] + ".info.json Music/" + sys.argv[1] + ".info.json > /dev/null 2> /dev/null") + os.system("rm -rf Temp/ > /dev/null 2> /dev/null") \ No newline at end of file