aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2021-06-19 13:51:37 +0200
committerdec05eba <dec05eba@protonmail.com>2021-06-19 13:51:37 +0200
commit5ec1811fa7499386f324f13a3a49dbe7d8ea6741 (patch)
tree835c8b853cc9a6f96aa962070d685e2e3e2f110d
parent85c6c916541968f298badb391b718cdf6d81d332 (diff)
Fix youtube sometimes needing a redirect for media url
-rw-r--r--include/QuickMedia.hpp1
-rw-r--r--plugins/Page.hpp6
-rw-r--r--src/QuickMedia.cpp77
-rw-r--r--src/plugins/Youtube.cpp30
4 files changed, 75 insertions, 39 deletions
diff --git a/include/QuickMedia.hpp b/include/QuickMedia.hpp
index a1656aa..7078791 100644
--- a/include/QuickMedia.hpp
+++ b/include/QuickMedia.hpp
@@ -192,6 +192,7 @@ namespace QuickMedia {
bool fit_image_to_window = false;
RoomData *current_chat_room = nullptr;
bool go_to_previous_page = false;
+ bool running_task_with_loading_screen = false;
sf::Text tab_text;
sf::Vertex gradient_points[4];
sf::Vector2f body_pos;
diff --git a/plugins/Page.hpp b/plugins/Page.hpp
index 0d45b9e..2d10d50 100644
--- a/plugins/Page.hpp
+++ b/plugins/Page.hpp
@@ -117,13 +117,15 @@ namespace QuickMedia {
std::string get_url() { return url; }
// Returns empty string for no timestamp or if the video doesn't support timestamps
virtual std::string get_url_timestamp() { return ""; }
- // Falls back to |get_url| if this and |get_audio_url| returns empty strings
+ // Falls back to |get_url| if this and |get_audio_url| returns empty strings.
+ // Might do a network request.
virtual std::string get_video_url(int max_height, bool &has_embedded_audio) {
(void)max_height;
has_embedded_audio = true;
return "";
}
- // Only used if |get_video_url| sets |has_embedded_audio| to false
+ // Only used if |get_video_url| sets |has_embedded_audio| to false.
+ // Might do a network request.
virtual std::string get_audio_url() { return ""; }
virtual std::string url_get_playable_url(const std::string &url) { return url; }
virtual bool video_should_be_skipped(const std::string &url) { (void)url; return false; }
diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp
index a4ea258..c02b9ab 100644
--- a/src/QuickMedia.cpp
+++ b/src/QuickMedia.cpp
@@ -2295,10 +2295,13 @@ namespace QuickMedia {
TaskResult Program::run_task_with_loading_screen(std::function<bool()> callback) {
assert(std::this_thread::get_id() == main_thread_id);
+ if(running_task_with_loading_screen)
+ return callback() ? TaskResult::TRUE : TaskResult::FALSE;
+ running_task_with_loading_screen = true;
idle_active_handler();
-
AsyncTask<bool> task = callback;
+ TaskResult task_result = TaskResult::TRUE;
window_size.x = window.getSize().x;
window_size.y = window.getSize().y;
@@ -2312,20 +2315,20 @@ namespace QuickMedia {
window.setView(sf::View(visible_area));
} else if(event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Escape) {
task.cancel();
- return TaskResult::CANCEL;
+ task_result = TaskResult::CANCEL;
+ goto task_end;
}
}
if(handle_window_close()) {
task.cancel();
- return TaskResult::CANCEL;
+ task_result = TaskResult::CANCEL;
+ goto task_end;
}
if(task.ready()) {
- if(task.get())
- return TaskResult::TRUE;
- else
- return TaskResult::FALSE;
+ task_result = task.get() ? TaskResult::TRUE : TaskResult::FALSE;
+ goto task_end;
}
window.clear(back_color);
@@ -2335,7 +2338,9 @@ namespace QuickMedia {
window.display();
}
- return TaskResult::TRUE;
+ task_end:
+ running_task_with_loading_screen = false;
+ return task_result;
}
static bool video_url_supports_timestamp(const std::string &url) {
@@ -2507,8 +2512,35 @@ namespace QuickMedia {
if(!reuse_media_source) {
std::string new_title;
- TaskResult load_result = run_task_with_loading_screen([video_page, &new_title, &channel_url, &media_chapters]() {
- return video_page->load(new_title, channel_url, media_chapters) == PluginResult::OK;
+ video_url.clear();
+ audio_url.clear();
+
+ TaskResult load_result = run_task_with_loading_screen([this, video_page, &new_title, &channel_url, &media_chapters, largest_monitor_height, &has_embedded_audio, &video_url, &audio_url, &is_audio_only, &previous_page, is_youtube, download_if_streaming_fails]() {
+ if(video_page->load(new_title, channel_url, media_chapters) != PluginResult::OK)
+ return false;
+
+ if(!no_video)
+ video_url = video_page->get_video_url(largest_monitor_height, has_embedded_audio);
+
+ if(video_url.empty() || no_video) {
+ video_url = video_page->get_audio_url();
+ if(video_url.empty()) {
+ video_url = video_page->get_url();
+ has_embedded_audio = true;
+ } else {
+ is_audio_only = true;
+ has_embedded_audio = false;
+ }
+ } else if(!has_embedded_audio) {
+ audio_url = video_page->get_audio_url();
+ }
+
+ if(!is_youtube && download_if_streaming_fails) {
+ if(!video_download_if_non_streamable(video_url, audio_url, is_audio_only, has_embedded_audio, previous_page))
+ return false;
+ }
+
+ return true;
});
if(!new_title.empty())
@@ -2524,31 +2556,6 @@ namespace QuickMedia {
go_to_previous_page = true;
return;
}
-
- video_url.clear();
- audio_url.clear();
- if(!no_video)
- video_url = video_page->get_video_url(largest_monitor_height, has_embedded_audio);
-
- if(video_url.empty() || no_video) {
- video_url = video_page->get_audio_url();
- if(video_url.empty()) {
- video_url = video_page->get_url();
- has_embedded_audio = true;
- } else {
- is_audio_only = true;
- has_embedded_audio = false;
- }
- } else if(!has_embedded_audio) {
- audio_url = video_page->get_audio_url();
- }
-
- if(!is_youtube && download_if_streaming_fails) {
- if(!video_download_if_non_streamable(video_url, audio_url, is_audio_only, has_embedded_audio, previous_page)) {
- go_to_previous_page = true;
- return;
- }
- }
}
const bool is_resume_go_back = !start_time.empty();
diff --git a/src/plugins/Youtube.cpp b/src/plugins/Youtube.cpp
index b45b5fe..717bc8f 100644
--- a/src/plugins/Youtube.cpp
+++ b/src/plugins/Youtube.cpp
@@ -1981,6 +1981,32 @@ R"END(
return nullptr;
}
+ // Sometimes youtube returns a redirect url (not in the header but in the body...).
+ // TODO: Find why this happens and if there is a way bypass it.
+ static std::string get_playback_url_recursive(std::string playback_url) {
+ const int max_redirects = 5;
+ for(int i = 0; i < max_redirects; ++i) {
+ std::string response_headers;
+ if(download_head_to_string(playback_url, response_headers, true) != DownloadResult::OK)
+ return "";
+
+ std::string content_type = header_extract_value(response_headers, "content-type");
+ if(content_type.empty())
+ return "";
+
+ if(string_starts_with(content_type, "video") || string_starts_with(content_type, "audio"))
+ return playback_url;
+
+ // TODO: Download head and body in one request
+ std::string new_url;
+ if(download_to_string(playback_url, new_url, {}, true) != DownloadResult::OK)
+ return "";
+
+ playback_url = std::move(new_url);
+ }
+ return playback_url;
+ }
+
std::string YoutubeVideoPage::get_video_url(int max_height, bool &has_embedded_audio) {
if(!hls_manifest_url.empty()) {
has_embedded_audio = true;
@@ -2007,7 +2033,7 @@ R"END(
print_chosen_format(*chosen_video_format);
has_embedded_audio = chosen_video_format->has_embedded_audio;
- return chosen_video_format->base.url;
+ return get_playback_url_recursive(chosen_video_format->base.url);
}
std::string YoutubeVideoPage::get_audio_url() {
@@ -2017,7 +2043,7 @@ R"END(
// TODO: The "worst" (but still good) quality audio is chosen right now because youtube seeking freezes for up to 15 seconds when choosing the best quality
const YoutubeAudioFormat *chosen_audio_format = &audio_formats.back();
fprintf(stderr, "Choosing youtube audio format: bitrate: %d, mime type: %s\n", chosen_audio_format->base.bitrate, chosen_audio_format->base.mime_type.c_str());
- return chosen_audio_format->base.url;
+ return get_playback_url_recursive(chosen_audio_format->base.url);
}
// Returns -1 if timestamp is in an invalid format