diff --git a/Tubio/ConsoleManager.cpp b/Tubio/ConsoleManager.cpp new file mode 100644 index 0000000..72853ea --- /dev/null +++ b/Tubio/ConsoleManager.cpp @@ -0,0 +1,98 @@ +#include "ConsoleManager.h" + +void ConsoleManager::PrePreInit() +{ +#ifdef _WIN + FreeConsole(); + AllocConsole(); + FILE* dummy; + freopen_s(&dummy, "CONOUT$", "wt", stdout); + freopen_s(&dummy, "CONOUT$", "wt", stderr); + freopen_s(&dummy, "CONOUT$", "rt", stdin); + consoleHandle = GetConsoleWindow(); +#endif + return; +} + +void ConsoleManager::PreInit() +{ + log = new Logging::Logger("ConsoleManager"); + isConsoleActive = XGConfig::general.show_console; + + return; +} + +void ConsoleManager::PostInit() +{ +#ifdef _WIN + if (isConsoleActive) + { + ShowWindow(consoleHandle, SW_SHOW); + BringWindowToTop(consoleHandle); + } + else + { + ShowWindow(consoleHandle, SW_HIDE); + } +#endif + + return; +} + +bool ConsoleManager::ShowConsole() +{ + #ifdef _WIN + if (!IsConsoleShown()) + { + ShowWindow(consoleHandle, SW_SHOW); + BringWindowToTop(consoleHandle); + XGConfig::general.show_console = true; + isConsoleActive = true; + return true; + } + #endif + return false; +} + +bool ConsoleManager::HideConsole() +{ + #ifdef _WIN + if (IsConsoleShown()) + { + ShowWindow(consoleHandle, SW_HIDE); + XGConfig::general.show_console = false; + isConsoleActive = false; + return true; + } + #endif + return false; +} + +bool ConsoleManager::IsConsoleShown() +{ + return isConsoleActive; +} + +bool ConsoleManager::IsSupported() +{ +#ifdef _WIN + return true; +#endif + return false; +} + +void ConsoleManager::PostExit() +{ + delete log; + log = nullptr; + + return; +} + + +bool ConsoleManager::isConsoleActive; +Logging::Logger* ConsoleManager::log; + +#ifdef _WIN +HWND ConsoleManager::consoleHandle; +#endif \ No newline at end of file diff --git a/Tubio/ConsoleManager.h b/Tubio/ConsoleManager.h new file mode 100644 index 0000000..d821fbe --- /dev/null +++ b/Tubio/ConsoleManager.h @@ -0,0 +1,35 @@ +#pragma once +#include "XGConfig.h" +#include "Logger.h" + +#undef _WIN + + +#ifdef _WIN +#include +#endif + +class ConsoleManager +{ +public: + static void PrePreInit(); + static void PreInit(); + static void PostInit(); + static void PostExit(); + + static bool ShowConsole(); + static bool HideConsole(); + static bool IsConsoleShown(); + + // Returns whether or not the current platform supports hiding the console + static bool IsSupported(); + +private: + static bool isConsoleActive; + static Logging::Logger* log; + +#ifdef _WIN + static HWND consoleHandle; +#endif +}; + diff --git a/Tubio/DownloadManager.cpp b/Tubio/DownloadManager.cpp index bebf3bf..a1590ea 100644 --- a/Tubio/DownloadManager.cpp +++ b/Tubio/DownloadManager.cpp @@ -83,14 +83,12 @@ std::string DownloadManager::QueueDownload(std::string url, DOWNLOAD_MODE mode) queue.push_back(newDownload); - Save(); - return tubioId; } void DownloadManager::Update() { - //if (shouldSave) Save(); + if (shouldSave) Save(); std::size_t numActiveDownloads = GetNumActiveDownloads(); @@ -131,7 +129,7 @@ void DownloadManager::DownloadNext() if (entry->mode == DOWNLOAD_MODE::VIDEO) { ss << "youtube-dl --newline --no-call-home --no-playlist --limit-rate " << XGConfig::downloader.max_dlrate_per_thread - << " --no-mtime --no-cache-dir --format \"bestvideo[ext=mp4]+bestaudio\" --merge-output-format mp4" + << " --no-mtime --no-cache-dir --format \"bestvideo[ext=mp4]+bestaudio/best[ext=mp4]/best\" --merge-output-format mp4" << " -o \"" << XGConfig::downloader.cachedir << "/download/" << entry->tubio_id << ".mp4\" " << entry->webpage_url << " > \"" << XGConfig::downloader.cachedir << "/dlprogbuf/" << entry->tubio_id << ".buf" << "\""; @@ -145,7 +143,8 @@ void DownloadManager::DownloadNext() << "/dlprogbuf/" << entry->tubio_id << ".buf" << "\""; } - system(ss.str().c_str()); + int returnCode = system(ss.str().c_str()); + std::cout << returnCode << std::endl; entry->status = DOWNLOAD_STATUS::FINISHED; entry->download_progress = 100; @@ -153,7 +152,7 @@ void DownloadManager::DownloadNext() return; }); downloadThreads.push_back(downloadThread); - + return; } @@ -187,6 +186,8 @@ void DownloadManager::UpdateDownloadProgressPercentages() { int newPercentage = std::stoi(ss.str()); queue[i].download_progress = newPercentage; + + //if (newPercentage == 100) queue[i].status = DOWNLOAD_STATUS::FINISHED; } } } @@ -238,6 +239,25 @@ void Downloader::DownloadManager::ClearDownloadCache() void DownloadManager::Save() { + log->cout << "Saving..."; + log->Flush(); + + if (downloadThreads.size() > 0) + { + log->cout << "Waiting for active download threads to finish before saving..."; + log->Flush(); + + for (std::size_t i = 0; i < downloadThreads.size(); i++) + { + downloadThreads[i]->join(); + delete downloadThreads[i]; + downloadThreads[i] = nullptr; + } + downloadThreads.clear(); + log->cout << "All threads have finished. Now saving..."; + log->Flush(); + } + JsonArray arr; for (std::size_t i = 0; i < queue.size(); i++) { @@ -256,6 +276,9 @@ void DownloadManager::Save() shouldSave = false; + log->cout << "Saved!"; + log->Flush(); + return; } @@ -285,7 +308,7 @@ void DownloadManager::Load() { JsonBlock iter = cachedArr[i].AsJson; DownloadEntry newEntry; - newEntry.download_progress = -1; + newEntry.download_progress = 100; newEntry.status = DOWNLOAD_STATUS::FINISHED; // All saved entries are finished... if ((iter.DoesExist("title")) && (iter["title"].GetDataType() == JDType::STRING)) @@ -392,27 +415,14 @@ std::size_t Downloader::DownloadManager::GetNumActiveDownloads() void DownloadManager::OnExit() { - if (downloadThreads.size() > 0) - { - log->cout << "Waiting for active download threads to finish..."; - log->Flush(); - - for (std::size_t i = 0; i < downloadThreads.size(); i++) - { - downloadThreads[i]->join(); - delete downloadThreads[i]; - downloadThreads[i] = nullptr; - } - } + Save(); // Clear dlprogbuf directory. if (FileSystem::ExistsDirectory(XGConfig::downloader.cachedir + "/dlprogbuf")) { FileSystem::DeleteDirectory(XGConfig::downloader.cachedir + "/dlprogbuf"); } - - - Save(); + return; } diff --git a/Tubio/Framework.cpp b/Tubio/Framework.cpp index c26cd00..75ef4f0 100644 --- a/Tubio/Framework.cpp +++ b/Tubio/Framework.cpp @@ -6,6 +6,8 @@ using namespace Downloader; Framework::Framework() { + ConsoleManager::PrePreInit(); + PreInit(); log = new Logger("Framework"); @@ -18,6 +20,10 @@ Framework::Framework() XGControl::keepServerRunning = true; + log = new Logger("Framework"); + log->cout << "Started Tubio server successfully!"; + log->Flush(); + return; } @@ -52,6 +58,7 @@ void Framework::PreInit() { LogHistory::PreInit(); XGConfig::PreInit(); + ConsoleManager::PreInit(); RestQueryHandler::PreInit(); DownloadManager::PreInit(); @@ -61,6 +68,7 @@ void Framework::PreInit() void Framework::PostInit() { + ConsoleManager::PostInit(); httpServer->PostInit(); return; @@ -80,6 +88,7 @@ void Framework::PostExit() RestQueryHandler::PostExit(); LogHistory::PostExit(); DownloadManager::PostExit(); + ConsoleManager::PostExit(); return; } diff --git a/Tubio/Framework.h b/Tubio/Framework.h index efb48de..7a6f3bf 100644 --- a/Tubio/Framework.h +++ b/Tubio/Framework.h @@ -3,6 +3,7 @@ #include "LogHistory.h" #include "HttpServer.h" #include "DownloadManager.h" +#include "ConsoleManager.h" #include "XGControl.h" #include "XGConfig.h" diff --git a/Tubio/HttpServer.cpp b/Tubio/HttpServer.cpp index b7b62d9..bacc563 100644 --- a/Tubio/HttpServer.cpp +++ b/Tubio/HttpServer.cpp @@ -60,7 +60,7 @@ bool HttpServer::InitWebServer() void HttpServer::Update() { - mg_mgr_poll(pMgr, XGConfig::httpServer.pollingRate); + mg_mgr_poll(pMgr, XGConfig::httpServer.polling_rate); return; } diff --git a/Tubio/RestQueryHandler.cpp b/Tubio/RestQueryHandler.cpp index 3a37191..71d7d8c 100644 --- a/Tubio/RestQueryHandler.cpp +++ b/Tubio/RestQueryHandler.cpp @@ -31,6 +31,9 @@ bool RestQueryHandler::ProcessQuery(const std::string clientAdress, const Json& else if (requestName == "fetch_queue") return FetchQueue(requestBody, responseBody, responseCode); else if (requestName == "clear_download_cache") return ClearDownloadCache(requestBody, responseBody, responseCode); else if (requestName == "foo") return Example_Foo(requestBody, responseBody, responseCode); + else if (requestName == "show_console") return ShowConsole(requestBody, responseBody, responseCode); + else if (requestName == "hide_console") return HideConsole(requestBody, responseBody, responseCode); + else if (requestName == "get_os_name") return GetOSName(requestBody, responseBody, responseCode); @@ -104,6 +107,10 @@ bool RestQueryHandler::ClearDownloadCache(const JsonBlock& request, JsonBlock& r responseCode = OK; responseBody.CloneFrom(RestResponseTemplates::GetByCode(OK)); DownloadManager::ClearDownloadCache(); + + log->cout << "Clearing download cache..."; + log->Flush(); + return true; } @@ -111,7 +118,7 @@ bool RestQueryHandler::KillYourself(const JsonBlock& request, JsonBlock& respons { XGControl::keepServerRunning = false; - log->cout << "Shutting down server upon rest request..."; + log->cout << "Shutting down server upon client request..."; log->Flush(); responseCode = OK; @@ -120,9 +127,63 @@ bool RestQueryHandler::KillYourself(const JsonBlock& request, JsonBlock& respons return true; } +bool RestQueryHandler::HideConsole(const JsonBlock& request, JsonBlock& responseBody, HTTP_STATUS_CODE& responseCode) +{ + if (ConsoleManager::IsSupported()) + { + bool didAnythingChange = ConsoleManager::HideConsole(); + responseCode = OK; + responseBody.CloneFrom(RestResponseTemplates::GetByCode(OK)); + responseBody.Set("message") = (didAnythingChange) ? "Console is now hidden!" : "Console was already hidden!"; + return true; + } + else + { + responseCode = NOT_IMPLEMENTED; + responseBody.CloneFrom(RestResponseTemplates::GetByCode(NOT_IMPLEMENTED)); + responseBody.Set("message") = "This feature is currently only supported on Windows! Make sure to compile with preprocessor directive _WIN!"; + return false; + } +} +bool RestQueryHandler::ShowConsole(const JsonBlock& request, JsonBlock& responseBody, HTTP_STATUS_CODE& responseCode) +{ + if (ConsoleManager::IsSupported()) + { + bool didAnythingChange = ConsoleManager::ShowConsole(); + responseCode = OK; + responseBody.CloneFrom(RestResponseTemplates::GetByCode(OK)); + responseBody.Set("message") = (didAnythingChange) ? "Console is now shown!" : "Console was already shown!"; + return true; + } + else + { + responseCode = NOT_IMPLEMENTED; + responseBody.CloneFrom(RestResponseTemplates::GetByCode(NOT_IMPLEMENTED)); + responseBody.Set("message") = "This feature is currently only supported on Windows! Make sure to compile with preprocessor directive _WIN!"; + return false; + } +} - +bool RestQueryHandler::GetOSName(const JsonBlock& request, JsonBlock& responseBody, HTTP_STATUS_CODE& responseCode) +{ + std::string osName = "other"; +#ifdef _WIN + osName = "Windows"; +#elif __APPLE__ || __MACH__ + osName = "Mac OSX"; +#elif __linux__ + osName = "Linux"; +#elif __FreeBSD__ + osName = "FreeBSD"; +#elif __unix || __unix__ + osName = "Unix"; +#endif + responseCode = OK; + responseBody.CloneFrom(RestResponseTemplates::GetByCode(OK)); + responseBody.Set("os_name") = osName; + return true; +} diff --git a/Tubio/RestQueryHandler.h b/Tubio/RestQueryHandler.h index acbed23..86717b0 100644 --- a/Tubio/RestQueryHandler.h +++ b/Tubio/RestQueryHandler.h @@ -4,6 +4,7 @@ #include "XGControl.h" #include "Logger.h" #include "DownloadManager.h" +#include "ConsoleManager.h" namespace Rest { @@ -22,6 +23,9 @@ namespace Rest static bool QueueDownload(const JasonPP::JsonBlock& request, JasonPP::JsonBlock& responseBody, HTTP_STATUS_CODE& responseCode); static bool ClearDownloadCache(const JasonPP::JsonBlock& request, JasonPP::JsonBlock& responseBody, HTTP_STATUS_CODE& responseCode); static bool KillYourself(const JasonPP::JsonBlock& request, JasonPP::JsonBlock& responseBody, HTTP_STATUS_CODE& responseCode); + static bool HideConsole(const JasonPP::JsonBlock& request, JasonPP::JsonBlock& responseBody, HTTP_STATUS_CODE& responseCode); + static bool ShowConsole(const JasonPP::JsonBlock& request, JasonPP::JsonBlock& responseBody, HTTP_STATUS_CODE& responseCode); + static bool GetOSName(const JasonPP::JsonBlock& request, JasonPP::JsonBlock& responseBody, HTTP_STATUS_CODE& responseCode); static bool ValidateField(const std::string name, const JasonPP::JDType type, const JasonPP::Json& checkThat, JasonPP::JsonBlock& putErrorResponseHere); diff --git a/Tubio/Tubio.vcxproj b/Tubio/Tubio.vcxproj index 0098af9..a4658cf 100644 --- a/Tubio/Tubio.vcxproj +++ b/Tubio/Tubio.vcxproj @@ -86,8 +86,9 @@ Level3 true - JASONPP_RENDER_SORTED;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + _WIN;_WIN32;JASONPP_RENDER_SORTED;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true + stdcpp17 Console @@ -100,8 +101,9 @@ true true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + _WIN;_WIN32;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true + stdcpp17 Console @@ -114,7 +116,7 @@ Level3 true - _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + _WIN;_WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true stdcpp17 @@ -129,8 +131,9 @@ true true true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + _WIN;_WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true + stdcpp17 Console @@ -140,6 +143,7 @@ + @@ -155,6 +159,7 @@ + diff --git a/Tubio/Tubio.vcxproj.filters b/Tubio/Tubio.vcxproj.filters index f4ecddd..f8da60d 100644 --- a/Tubio/Tubio.vcxproj.filters +++ b/Tubio/Tubio.vcxproj.filters @@ -57,6 +57,9 @@ Quelldateien + + Quelldateien + @@ -98,5 +101,8 @@ Headerdateien + + Headerdateien + \ No newline at end of file diff --git a/Tubio/XGConfig.cpp b/Tubio/XGConfig.cpp index 65b1ab1..75ccb62 100644 --- a/Tubio/XGConfig.cpp +++ b/Tubio/XGConfig.cpp @@ -33,7 +33,7 @@ bool XGConfig::IsJsonFieldValid(const JsonBlock& json, const std::string key, co void XGConfig::InitializeDefaultValues() { httpServer.port = "6969"; - httpServer.pollingRate = 100; + httpServer.polling_rate = 100; httpServer.rootdir = "frontend"; logging.logfile_text = "log.txt"; @@ -48,6 +48,8 @@ void XGConfig::InitializeDefaultValues() downloader.loginCredentials.password = ""; downloader.loginCredentials.twofactor = ""; + general.show_console = true; + return; } @@ -70,9 +72,9 @@ void XGConfig::LoadFromJson(const JasonPP::JsonBlock& json) httpServer.port = json.ShorthandGet("httpServer.port").AsString; } - if (IsJsonFieldValid(json, "httpServer.pollingRate", JDType::INT)) + if (IsJsonFieldValid(json, "httpServer.polling_rate", JDType::INT)) { - httpServer.pollingRate = json.ShorthandGet("httpServer.pollingRate").AsInt; + httpServer.polling_rate = json.ShorthandGet("httpServer.polling_rate").AsInt; } if (IsJsonFieldValid(json, "httpServer.rootdir", JDType::STRING)) @@ -111,6 +113,11 @@ void XGConfig::LoadFromJson(const JasonPP::JsonBlock& json) { downloader.loginCredentials.twofactor = json.ShorthandGet("downloader.loginCredentials.twofactor").AsString; } + + if (IsJsonFieldValid(json, "general.show_console", JDType::BOOL)) + { + general.show_console = json.ShorthandGet("general.show_console").AsBool; + } return; } @@ -120,7 +127,7 @@ JsonBlock XGConfig::CreateJson() return JsonBlock({ Ele("httpServer", JsonBlock({ Ele("port", httpServer.port), - Ele("pollingRate", httpServer.pollingRate), + Ele("pollingRate", httpServer.polling_rate), Ele("rootdir", httpServer.rootdir) })), Ele("logging", JsonBlock({ @@ -137,6 +144,9 @@ JsonBlock XGConfig::CreateJson() Ele("password", downloader.loginCredentials.password), Ele("twofactor", downloader.loginCredentials.twofactor) })) + })), + Ele("general", JsonBlock({ + Ele("show_console", general.show_console) })) }); } @@ -249,4 +259,6 @@ void XGConfig::Load() XGConfig::HttpServer XGConfig::httpServer; XGConfig::Logging XGConfig::logging; XGConfig::Downloader XGConfig::downloader; +XGConfig::General XGConfig::general; + ::Logging::Logger* XGConfig::log; diff --git a/Tubio/XGConfig.h b/Tubio/XGConfig.h index 2c8a241..a6ab945 100644 --- a/Tubio/XGConfig.h +++ b/Tubio/XGConfig.h @@ -13,7 +13,7 @@ public: { std::string port; std::string rootdir; - int pollingRate; + int polling_rate; }; struct Logging { @@ -36,14 +36,19 @@ public: int num_threads; }; + struct General + { + bool show_console; + }; static void PreInit(); static void Save(); static void PostExit(); - static HttpServer httpServer; + static XGConfig::HttpServer httpServer; static XGConfig::Logging logging; static XGConfig::Downloader downloader; + static XGConfig::General general; static ::Logging::Logger* log;