diff --git a/Tubio/$$DL_PROG_BUF_FILE b/Tubio/$$DL_PROG_BUF_FILE
new file mode 100644
index 0000000..6221ed3
--- /dev/null
+++ b/Tubio/$$DL_PROG_BUF_FILE
@@ -0,0 +1,21 @@
+[youtube] eJsTaFRsa_k: Downloading webpage
+[youtube] Downloading just video eJsTaFRsa_k because of --no-playlist
+[youtube] eJsTaFRsa_k: Downloading js player 12237e3d
+[youtube] eJsTaFRsa_k: Downloading js player 12237e3d
+[download] Destination: dlcache\download\1KmyoJ.webm
+[download] 0.0% of 6.60MiB at 249.94KiB/s ETA 00:27
+[download] 0.0% of 6.60MiB at 749.83KiB/s ETA 00:09
+[download] 0.1% of 6.60MiB at 1.71MiB/s ETA 00:03
+[download] 0.2% of 6.60MiB at 3.66MiB/s ETA 00:01
+[download] 0.5% of 6.60MiB at 1.59MiB/s ETA 00:04
+[download] 0.9% of 6.60MiB at 1.71MiB/s ETA 00:03
+[download] 1.9% of 6.60MiB at 2.48MiB/s ETA 00:02
+[download] 3.8% of 6.60MiB at 3.61MiB/s ETA 00:01
+[download] 7.6% of 6.60MiB at 5.73MiB/s ETA 00:01
+[download] 15.1% of 6.60MiB at 8.32MiB/s ETA 00:00
+[download] 30.3% of 6.60MiB at 14.17MiB/s ETA 00:00
+[download] 60.6% of 6.60MiB at 17.77MiB/s ETA 00:00
+[download] 100.0% of 6.60MiB at 28.45MiB/s ETA 00:00
+[download] 100% of 6.60MiB in 00:00
+[ffmpeg] Destination: dlcache\download\1KmyoJ.mp3
+Deleting original file dlcache\download\1KmyoJ.webm (pass -k to keep)
diff --git a/Tubio/DownloadManager.cpp b/Tubio/DownloadManager.cpp
index 92cc255..48705b7 100644
--- a/Tubio/DownloadManager.cpp
+++ b/Tubio/DownloadManager.cpp
@@ -28,6 +28,7 @@ std::string DownloadManager::QueueDownload(std::string url, DOWNLOAD_MODE mode)
newDownload.tubio_id = tubioId;
newDownload.mode = mode;
newDownload.download_progress = 0;
+ newDownload.download_url = "/download/" + newDownload.tubio_id;
if (!IsJsonValid(jsString))
{
@@ -145,35 +146,36 @@ void DownloadManager::DownloadNext()
std::stringstream ss;
if (entry->mode == DOWNLOAD_MODE::VIDEO)
{
- std::string ytdl_call_video =
- "youtube-dl --newline --no-call-home --no-playlist --limit-rate $$DL_RATE"
- " --no-mtime --no-cache-dir --format \"bestvideo[ext=mp4]+bestaudio/best[ext=mp4]/best\""
+ std::string ytdl_call_video_base =
+ "youtube-dl --newline --no-call-home --no-playlist --no-part --no-warnings --limit-rate $$DL_RATE"
+ " --no-mtime --no-cache-dir --recode-video mp4 --format \"bestvideo[ext=mp4]+bestaudio/best[ext=mp4]/best\""
" --merge-output-format mp4 -o \"$$DL_FILE\" $$DL_URL > \"$$DL_PROG_BUF_FILE\"";
- ytdl_call_video = Internal::StringHelpers::Replace(ytdl_call_video, "$$DL_RATE", XGConfig::downloader.max_dlrate_per_thread);
- ytdl_call_video = Internal::StringHelpers::Replace(ytdl_call_video, "$$DL_FILE", XGConfig::downloader.cachedir + "/download/" + entry->tubio_id + ".%(ext)s");
- ytdl_call_video = Internal::StringHelpers::Replace(ytdl_call_video, "$$DL_URL", entry->webpage_url);
- ytdl_call_video = Internal::StringHelpers::Replace(ytdl_call_video, "$$DL_PROG_BUF_FILE", XGConfig::downloader.cachedir + "/dlprogbuf/" + entry->tubio_id + ".buf");
+ ytdl_call_video_base = Internal::StringHelpers::Replace(ytdl_call_video_base, "$$DL_RATE", XGConfig::downloader.max_dlrate_per_thread);
+ ytdl_call_video_base = Internal::StringHelpers::Replace(ytdl_call_video_base, "$$DL_FILE", XGConfig::downloader.cachedir + "/download/" + entry->tubio_id + ".%(ext)s");
+ ytdl_call_video_base = Internal::StringHelpers::Replace(ytdl_call_video_base, "$$DL_URL", entry->webpage_url);
+ ytdl_call_video_base = Internal::StringHelpers::Replace(ytdl_call_video_base, "$$DL_PROG_BUF_FILE", XGConfig::downloader.cachedir + "/dlprogbuf/" + entry->tubio_id + ".buf");
- ss << ytdl_call_video;
+ entry->downloaded_filename = XGConfig::downloader.cachedir + "/download/" + entry->tubio_id + ".mp4";
+ ss << ytdl_call_video_base;
}
else // DOWNLOAD_MODE::AUDIO
{
- std::string ytdl_call_audio =
- "youtube-dl --newline --no-call-home --no-playlist --limit-rate $$DL_RATE"
+ std::string ytdl_call_audio_base =
+ "youtube-dl --newline --no-call-home --no-playlist --no-part --no-warnings --limit-rate $$DL_RATE"
" --no-mtime --no-cache-dir --audio-format mp3 --audio-quality 0 --extract-audio -o \"$$DL_FILE\""
" $$DL_URL > \"$$DL_PROG_BUF_FILE\"";
- ytdl_call_audio = Internal::StringHelpers::Replace(ytdl_call_audio, "$$DL_RATE", XGConfig::downloader.max_dlrate_per_thread);
- ytdl_call_audio = Internal::StringHelpers::Replace(ytdl_call_audio, "$$DL_FILE", XGConfig::downloader.cachedir + "/download/" + entry->tubio_id + ".%(ext)s");
- ytdl_call_audio = Internal::StringHelpers::Replace(ytdl_call_audio, "$$DL_URL", entry->webpage_url);
- ytdl_call_audio = Internal::StringHelpers::Replace(ytdl_call_audio, "$$DL_PROG_BUF_FILE", XGConfig::downloader.cachedir + "/dlprogbuf/" + entry->tubio_id + ".buf");
+ ytdl_call_audio_base = Internal::StringHelpers::Replace(ytdl_call_audio_base, "$$DL_RATE", XGConfig::downloader.max_dlrate_per_thread);
+ ytdl_call_audio_base = Internal::StringHelpers::Replace(ytdl_call_audio_base, "$$DL_FILE", XGConfig::downloader.cachedir + "/download/" + entry->tubio_id + ".%(ext)s");
+ ytdl_call_audio_base = Internal::StringHelpers::Replace(ytdl_call_audio_base, "$$DL_URL", entry->webpage_url);
+ ytdl_call_audio_base = Internal::StringHelpers::Replace(ytdl_call_audio_base, "$$DL_PROG_BUF_FILE", XGConfig::downloader.cachedir + "/dlprogbuf/" + entry->tubio_id + ".buf");
- ss << ytdl_call_audio;
+ entry->downloaded_filename = XGConfig::downloader.cachedir + "/download/" + entry->tubio_id + ".mp3";
+ ss << ytdl_call_audio_base;
}
int returnCode = system(ss.str().c_str());
- std::cout << returnCode << std::endl;
if (returnCode == 0)
{
@@ -263,6 +265,26 @@ JsonArray DownloadManager::GetQueueAsJson()
return arr;
}
+bool DownloadManager::DoesTubioIDExist(std::string tubioId)
+{
+ for (std::size_t i = 0; i < queue.size(); i++)
+ {
+ if (queue[i].tubio_id == tubioId) return true;
+ }
+ return false;
+}
+
+DownloadEntry& DownloadManager::GetDownloadEntryByTubioID(std::string tubioId)
+{
+ for (std::size_t i = 0; i < queue.size(); i++)
+ {
+ if (queue[i].tubio_id == tubioId) return queue[i];
+ }
+ throw std::exception("TubioID not found!");
+ std::terminate();
+}
+
+
bool DownloadManager::ClearDownloadCache()
{
if (GetNumActiveDownloads() == 0)
@@ -397,6 +419,16 @@ void DownloadManager::Load()
newEntry.thumbnail_url = iter["thumbnail_url"];
}
+ if ((iter.DoesExist("download_url")) && (iter["download_url"].GetDataType() == JDType::STRING))
+ {
+ newEntry.download_url = iter["download_url"];
+ }
+
+ if ((iter.DoesExist("downloaded_filename")) && (iter["downloaded_filename"].GetDataType() == JDType::STRING))
+ {
+ newEntry.downloaded_filename = iter["downloaded_filename"];
+ }
+
if ((iter.DoesExist("mode")) && (iter["mode"].GetDataType() == JDType::STRING))
{
std::string cachedStrMode = iter["mode"];
@@ -507,6 +539,8 @@ JsonBlock DownloadEntry::GetAsJson()
jb.Set(Ele("webpage_url", webpage_url));
jb.Set(Ele("thumbnail_url", thumbnail_url));
jb.Set(Ele("download_progress", download_progress));
+ jb.Set(Ele("downloaded_filename", downloaded_filename));
+ jb.Set(Ele("download_url", download_url));
switch (mode)
{
diff --git a/Tubio/DownloadManager.h b/Tubio/DownloadManager.h
index 7f0ce05..326caa6 100644
--- a/Tubio/DownloadManager.h
+++ b/Tubio/DownloadManager.h
@@ -34,6 +34,8 @@ namespace Downloader
std::string tubio_id;
std::string webpage_url;
std::string thumbnail_url;
+ std::string downloaded_filename;
+ std::string download_url;
DOWNLOAD_STATUS status;
DOWNLOAD_MODE mode;
int download_progress;
@@ -64,8 +66,24 @@ namespace Downloader
///
static std::size_t GetQueueLength();
+ ///
+ /// Will return the whole queue in json format
+ ///
+ ///
static JasonPP::JsonArray GetQueueAsJson();
+ ///
+ /// Returns whether or not a tubio id exists
+ ///
+ /// The id to check
+ static bool DoesTubioIDExist(std::string tubioId);
+
+ ///
+ /// Returns a reference to a DownloadEntry by its tubio id
+ ///
+ /// The corresponding tubio id
+ static DownloadEntry& GetDownloadEntryByTubioID(std::string tubioId);
+
///
/// Will delete all cached downloads!
/// If downloads are currently active, tubio will wait for them to finish and return false!
diff --git a/Tubio/HttpServer.cpp b/Tubio/HttpServer.cpp
index bacc563..35d56a6 100644
--- a/Tubio/HttpServer.cpp
+++ b/Tubio/HttpServer.cpp
@@ -88,6 +88,10 @@ void HttpServer::EventHandler(mg_connection* pNc, int ev, void* p)
{
ProcessAPIRequest(pNc, ev, p);
}
+ else if (requestedUri.substr(0, 9) == "/download")
+ {
+ ServeDownloadedResource(pNc, ev, p, requestedUri);
+ }
else
{
// Just serve the files requested
@@ -103,7 +107,7 @@ void HttpServer::EventHandler(mg_connection* pNc, int ev, void* p)
catch (...)
{
Json j;
- j.CloneFrom(RestResponseTemplates::GetByCode(INTERNAL_SERVER_ERROR, "Das not gud"));
+ j.CloneFrom(RestResponseTemplates::GetByCode(INTERNAL_SERVER_ERROR, "Das not good"));
ServeStringToConnection(pNc, j.Render(), INTERNAL_SERVER_ERROR);
}
@@ -147,6 +151,40 @@ void HttpServer::ProcessAPIRequest(mg_connection* pNc, int ev, void* p)
return;
}
+void HttpServer::ServeDownloadedResource(mg_connection* pNc, int ev, void* p, std::string uri)
+{
+ std::string fileId = uri.substr(10, uri.length() - 10);
+
+ if (Downloader::DownloadManager::DoesTubioIDExist(fileId))
+ {
+ Downloader::DownloadEntry& entry = Downloader::DownloadManager::GetDownloadEntryByTubioID(fileId);
+
+ if (entry.status == Downloader::DOWNLOAD_STATUS::FINISHED)
+ {
+ std::stringstream ss;
+ std::string downloadedFilename = entry.title + (entry.mode == Downloader::DOWNLOAD_MODE::AUDIO ? ".mp3" : ".mp4");
+
+ ss << "Access-Control-Allow-Origin: *\nContent-Disposition: attachment; filename=\"" << downloadedFilename << "\"\nPragma: public\nCache-Control: must-revalidate, post-check=0, pre-check=0";
+
+ mg_http_serve_file(pNc, (http_message*)p, entry.downloaded_filename.c_str(), mg_mk_str("application/octet-stream"), mg_mk_str(ss.str().c_str()));
+ }
+ else
+ {
+ Json j;
+ j.CloneFrom(RestResponseTemplates::GetByCode(BAD_REQUEST, "File download not ready!"));
+ ServeStringToConnection(pNc, j.Render(), BAD_REQUEST);
+ }
+ }
+ else
+ {
+ Json j;
+ j.CloneFrom(RestResponseTemplates::GetByCode(BAD_REQUEST, "Invalid file id!"));
+ ServeStringToConnection(pNc, j.Render(), BAD_REQUEST);
+ }
+
+ return;
+}
+
void HttpServer::OnExit()
{
log->cout << "Shutting down http-server...";
diff --git a/Tubio/HttpServer.h b/Tubio/HttpServer.h
index 1456478..13d727f 100644
--- a/Tubio/HttpServer.h
+++ b/Tubio/HttpServer.h
@@ -23,6 +23,7 @@ namespace Rest
private:
bool InitWebServer();
static void ProcessAPIRequest(struct mg_connection* pNc, int ev, void* p);
+ static void ServeDownloadedResource(struct mg_connection* pNc, int ev, void* p, std::string uri);
static void EventHandler(struct mg_connection* pNc, int ev, void* p);
static void ServeStringToConnection(struct mg_connection* c, std::string str, int httpStatusCode = 200);
diff --git a/Tubio/frontend/index.html b/Tubio/frontend/index.html
deleted file mode 100644
index 6e63e9e..0000000
--- a/Tubio/frontend/index.html
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-
-
-
- Hello, World!
-
-
-
-
-
-
-
- Hello, World!
-
-
-
-
-
-
-
diff --git a/Tubio/frontend/script.js b/Tubio/frontend/script.js
deleted file mode 100644
index a016338..0000000
--- a/Tubio/frontend/script.js
+++ /dev/null
@@ -1,27 +0,0 @@
-$(".button").mousedown(function(e){
- // Animations
- e.target.classList.add("clicked");
- setTimeout(function(){
- e.target.classList.remove("clicked");
- }, 100);
-});
-
-$("#btn_foo").click(function(e){
- // Functionality
- axios.post("/api", {
- request: "foo"
- }).then(function(response){
- // Do something with the servers response
- });
-});
-
-$("#btn_killserver").click(function(e){
- // Functionality
- axios.post("/api", {
- request: "kill_yourself"
- }).then(function(response){
- if (response.data.status == "OK") {
- $("#headline").html("Sever's dead");
- }
- });
-});
diff --git a/Tubio/frontend/style.css b/Tubio/frontend/style.css
deleted file mode 100644
index 06668af..0000000
--- a/Tubio/frontend/style.css
+++ /dev/null
@@ -1,75 +0,0 @@
-body {
- background-color: #00aa77;
-}
-
-h1,
-h2,
-h3,
-h4,
-p {
- font-family: sans-serif;
- color: #fff;
-}
-
-h1 {
- font-size: 38pt;
- text-align: center;
-}
-
-.button-wrapper {
- display: flex;
- width: 100%;
- height: 100%;
- align-items: center;
- flex-direction: column;
-}
-
-.button {
- background-color: #ee8800;
- padding: 0.5em 8em;
- width: 200px;
- border-radius: 1em;
- cursor: pointer;
- text-align: center;
- user-select: none;
-
- transition:
- background-color 0.2s,
- transform 0.2s;
-}
-
-@media (max-width: 600px) {
- .button {
- width: 80%;
- padding: 0.15em 3em;
- }
-}
-
-.button:first-child
-{
- margin-top: 5em;
-}
-.button:not(:first-child)
-{
- margin-top: 2em;
-}
-
-@media (min-width: 600px) {
- .button:hover {
- background-color: #ffaa00;
- transform: scale(1.05);
- }
-}
-
-.button.clicked {
- background-color: #cc6600;
- transform: scale(0.95);
-}
-
-.button p{
- font-size: 24pt;
-}
-
-.button * {
- pointer-events: none;
-}