aboutsummaryrefslogtreecommitdiff
path: root/src/QuickMedia.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/QuickMedia.cpp')
-rw-r--r--src/QuickMedia.cpp289
1 files changed, 163 insertions, 126 deletions
diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp
index c81d59d..c6a1d2f 100644
--- a/src/QuickMedia.cpp
+++ b/src/QuickMedia.cpp
@@ -2376,6 +2376,76 @@ namespace QuickMedia {
return url.substr(timestamp_start, timestamp_end - timestamp_start);
}
+ bool Program::video_download_if_non_streamable(std::string &video_url, std::string &audio_url, bool &is_audio_only, bool &has_embedded_audio, PageType previous_page) {
+ Path video_cache_dir = get_cache_dir().join("media");
+ Path video_path = video_cache_dir;
+ SHA256 sha256;
+ sha256.add(video_url.data(), video_url.size());
+ video_path.join(sha256.getHash());
+
+ if(get_file_type(video_path) == FileType::REGULAR) {
+ fprintf(stderr, "%s is found in cache. Playing from cache...\n", video_url.c_str());
+ video_url = std::move(video_path.data);
+ audio_url.clear();
+ if(no_video) {
+ is_audio_only = true;
+ has_embedded_audio = false;
+ } else {
+ is_audio_only = false;
+ has_embedded_audio = true;
+ }
+ } else {
+ TaskResult video_is_not_streamble_result = run_task_with_loading_screen([video_url]() {
+ return video_url_is_non_streamable_mp4(video_url.c_str());
+ });
+
+ if(video_is_not_streamble_result == TaskResult::TRUE) {
+ fprintf(stderr, "%s is detected to be a non-streamable mp4 file, downloading it before playing it...\n", video_url.c_str());
+ if(create_directory_recursive(video_cache_dir) != 0) {
+ show_notification("QuickMedia", "Failed to create video cache directory", Urgency::CRITICAL);
+ current_page = previous_page;
+ go_to_previous_page = true;
+ return false;
+ }
+
+ TaskResult download_file_result = run_task_with_loading_screen([&video_path, video_url]() {
+ return download_to_file(video_url, video_path.data, {}, true) == DownloadResult::OK;
+ });
+ switch(download_file_result) {
+ case TaskResult::TRUE: {
+ video_url = std::move(video_path.data);
+ audio_url.clear();
+ if(no_video) {
+ is_audio_only = true;
+ has_embedded_audio = false;
+ } else {
+ is_audio_only = false;
+ has_embedded_audio = true;
+ }
+ break;
+ }
+ case TaskResult::FALSE: {
+ show_notification("QuickMedia", "Failed to download " + video_url, Urgency::CRITICAL);
+ current_page = previous_page;
+ go_to_previous_page = true;
+ return false;
+ }
+ case TaskResult::CANCEL: {
+ current_page = previous_page;
+ go_to_previous_page = true;
+ return false;
+ }
+ }
+ } else if(video_is_not_streamble_result == TaskResult::CANCEL) {
+ current_page = previous_page;
+ go_to_previous_page = true;
+ return false;
+ }
+ }
+
+ return true;
+ }
+
#define CLEANMASK(mask) ((mask) & (ShiftMask|ControlMask|Mod1Mask|Mod4Mask|Mod5Mask))
void Program::video_content_page(Page *parent_page, VideoPage *video_page, std::string video_title, bool download_if_streaming_fails, BodyItems &next_play_items, int play_index, int *parent_body_page, const std::string &parent_page_search) {
@@ -2406,127 +2476,77 @@ namespace QuickMedia {
std::function<void(const char*)> video_event_callback;
bool go_to_previous_page = false;
- auto load_video_error_check = [this, &video_title, &video_tasks, &channel_url, previous_page, &go_to_previous_page, &time_watched_timer, &video_loaded, video_page, &video_event_callback, &on_window_create, &video_player_window, is_youtube, is_matrix, download_if_streaming_fails](bool resume_video) mutable {
+ std::string video_url;
+ std::string audio_url;
+
+ bool in_seeking = false;
+ sf::Clock seeking_start_timer;
+ const float seeking_restart_timeout_sec = 4.0f; // TODO: Test if this timeout is good on slow hardware such as pinephone and slow internet
+
+ auto load_video_error_check = [this, &in_seeking, &video_url, &audio_url, &video_title, &video_tasks, &channel_url, previous_page, &go_to_previous_page, &time_watched_timer, &video_loaded, video_page, &video_event_callback, &on_window_create, &video_player_window, is_youtube, is_matrix, download_if_streaming_fails](std::string start_time = "", bool reuse_media_source = false) mutable {
video_player.reset();
channel_url.clear();
video_loaded = false;
+ in_seeking = false;
video_player_window = None;
-
- std::string new_title;
- TaskResult load_result = run_task_with_loading_screen([video_page, &new_title, &channel_url]() {
- return video_page->load(new_title, channel_url) == PluginResult::OK;
- });
-
- if(!new_title.empty())
- video_title = std::move(new_title);
-
- if(load_result == TaskResult::CANCEL) {
- current_page = previous_page;
- go_to_previous_page = true;
- return;
- } else if(load_result == TaskResult::FALSE) {
- show_notification("QuickMedia", "Failed to load media", Urgency::CRITICAL);
- current_page = previous_page;
- go_to_previous_page = true;
- return;
- }
bool is_audio_only = no_video;
bool has_embedded_audio = true;
const int largest_monitor_height = get_largest_monitor_height(disp);
- std::string video_url = video_page->get_video_url(largest_monitor_height, has_embedded_audio);
- std::string audio_url;
- 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();
- }
-
- bool video_url_is_local = false;
- if(!is_youtube && download_if_streaming_fails) {
- Path video_cache_dir = get_cache_dir().join("media");
- Path video_path = video_cache_dir;
- SHA256 sha256;
- sha256.add(video_url.data(), video_url.size());
- video_path.join(sha256.getHash());
- if(get_file_type(video_path) == FileType::REGULAR) {
- fprintf(stderr, "%s is found in cache. Playing from cache...\n", video_url.c_str());
- video_url = std::move(video_path.data);
- video_url_is_local = true;
- audio_url.clear();
- if(no_video) {
+
+ if(!reuse_media_source) {
+ std::string new_title;
+ TaskResult load_result = run_task_with_loading_screen([video_page, &new_title, &channel_url]() {
+ return video_page->load(new_title, channel_url) == PluginResult::OK;
+ });
+
+ if(!new_title.empty())
+ video_title = std::move(new_title);
+
+ if(load_result == TaskResult::CANCEL) {
+ current_page = previous_page;
+ go_to_previous_page = true;
+ return;
+ } else if(load_result == TaskResult::FALSE) {
+ show_notification("QuickMedia", "Failed to load media", Urgency::CRITICAL);
+ current_page = previous_page;
+ 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 {
- is_audio_only = false;
- has_embedded_audio = true;
}
- } else {
- TaskResult video_is_not_streamble_result = run_task_with_loading_screen([video_url]() {
- return video_url_is_non_streamable_mp4(video_url.c_str());
- });
- if(video_is_not_streamble_result == TaskResult::TRUE) {
- fprintf(stderr, "%s is detected to be a non-streamable mp4 file, downloading it before playing it...\n", video_url.c_str());
- if(create_directory_recursive(video_cache_dir) != 0) {
- show_notification("QuickMedia", "Failed to create video cache directory", Urgency::CRITICAL);
- current_page = previous_page;
- go_to_previous_page = true;
- return;
- }
+ } else if(!has_embedded_audio) {
+ audio_url = video_page->get_audio_url();
+ }
- TaskResult download_file_result = run_task_with_loading_screen([&video_path, video_url]() {
- return download_to_file(video_url, video_path.data, {}, true) == DownloadResult::OK;
- });
- switch(download_file_result) {
- case TaskResult::TRUE: {
- video_url = std::move(video_path.data);
- video_url_is_local = true;
- audio_url.clear();
- if(no_video) {
- is_audio_only = true;
- has_embedded_audio = false;
- } else {
- is_audio_only = false;
- has_embedded_audio = true;
- }
- break;
- }
- case TaskResult::FALSE: {
- show_notification("QuickMedia", "Failed to download " + video_url, Urgency::CRITICAL);
- current_page = previous_page;
- go_to_previous_page = true;
- return;
- }
- case TaskResult::CANCEL: {
- current_page = previous_page;
- go_to_previous_page = true;
- return;
- }
- }
- } else if(video_is_not_streamble_result == TaskResult::CANCEL) {
- current_page = previous_page;
- go_to_previous_page = true;
+ 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;
- }
}
}
- std::string start_time;
- if(is_youtube)
+ const bool is_resume_go_back = !start_time.empty();
+ if(is_youtube && start_time.empty())
start_time = youtube_url_extract_timestamp(video_page->get_url());
time_watched_timer.restart();
watched_videos.insert(video_page->get_url());
- video_player = std::make_unique<VideoPlayer>(is_audio_only, use_system_mpv_config, resume_video, is_matrix && !is_youtube, video_event_callback, on_window_create, resources_root, largest_monitor_height);
- VideoPlayer::Error err = video_player->load_video(video_url.c_str(), audio_url.c_str(), window.getSystemHandle(), plugin_name, video_title, start_time);
+ video_player = std::make_unique<VideoPlayer>(is_audio_only, use_system_mpv_config, is_matrix && !is_youtube, video_event_callback, on_window_create, resources_root, largest_monitor_height);
+ VideoPlayer::Error err = video_player->load_video(video_url.c_str(), audio_url.c_str(), window.getSystemHandle(), is_youtube, video_title, start_time);
if(err != VideoPlayer::Error::OK) {
std::string err_msg = "Failed to play url: ";
err_msg += video_page->get_url();
@@ -2537,15 +2557,17 @@ namespace QuickMedia {
if(video_page->autoplay_next_item())
return;
- std::string url = video_page->get_url();
- video_tasks = AsyncTask<BodyItems>([video_page, url]() {
- BodyItems related_videos = video_page->get_related_media(url);
- video_page->mark_watched();
- return related_videos;
- });
+ if(!is_resume_go_back) {
+ std::string url = video_page->get_url();
+ video_tasks = AsyncTask<BodyItems>([video_page, url]() {
+ BodyItems related_videos = video_page->get_related_media(url);
+ video_page->mark_watched();
+ return related_videos;
+ });
+ }
// TODO: Make this also work for other video plugins
- if(strcmp(plugin_name, "youtube") != 0 || resume_video)
+ if(strcmp(plugin_name, "youtube") != 0 || is_resume_go_back)
return;
std::string video_id;
@@ -2580,29 +2602,35 @@ namespace QuickMedia {
}
};
- video_event_callback = [this, &time_watched_timer, &video_loaded](const char *event_name) mutable {
+ video_event_callback = [&time_watched_timer, &video_loaded, &in_seeking, &seeking_start_timer](const char *event_name) mutable {
+ if(strcmp(event_name, "seek") == 0) {
+ in_seeking = true;
+ seeking_start_timer.restart();
+ }
+
if(strcmp(event_name, "pause") == 0) {
//double time_remaining = 9999.0;
//if(video_player->get_time_remaining(&time_remaining) == VideoPlayer::Error::OK && time_remaining <= 1.0)
// end_of_file = true;
} else if(strcmp(event_name, "playback-restart") == 0) {
//video_player->set_paused(false);
+ in_seeking = false;
} else if(strcmp(event_name, "file-loaded") == 0) {
time_watched_timer.restart();
- if(!video_loaded)
- video_player->set_property("no-resume-playback", true);
video_loaded = true;
+ in_seeking = false;
} else if(strcmp(event_name, "video-reconfig") == 0 || strcmp(event_name, "audio-reconfig") == 0) {
if(!video_loaded) {
video_loaded = true;
time_watched_timer.restart();
}
+ in_seeking = false;
}
//fprintf(stderr, "event name: %s\n", event_name);
};
- load_video_error_check(false);
+ load_video_error_check();
sf::Event event;
@@ -2647,11 +2675,13 @@ namespace QuickMedia {
window_set_fullscreen(disp, window.getSystemHandle(), WindowFullscreenState::TOGGLE);
} else if(event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::C && event.key.control) {
save_video_url_to_clipboard();
+ } else if(event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::F5) {
+ load_video_error_check();
}
}
handle_window_close();
- if(video_player_window && XCheckTypedWindowEvent(disp, video_player_window, KeyPress, &xev)/* && xev.xkey.subwindow == video_player_window*/) {
+ if(video_player && video_player_window && XCheckTypedWindowEvent(disp, video_player_window, KeyPress, &xev)/* && xev.xkey.subwindow == video_player_window*/) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
KeySym pressed_keysym = XKeycodeToKeysym(disp, xev.xkey.keycode, 0);
@@ -2669,6 +2699,11 @@ namespace QuickMedia {
window_set_fullscreen(disp, window.getSystemHandle(), WindowFullscreenState::TOGGLE);
} else if(pressed_keysym == XK_s && pressing_ctrl) {
video_page_download_video(video_page->get_url(), !is_matrix || is_youtube, video_player_window);
+ } else if(pressed_keysym == XK_F5) {
+ in_seeking = false;
+ double resume_start_time = 0.0;
+ video_player->get_time_in_file(&resume_start_time);
+ load_video_error_check(std::to_string((int)resume_start_time));
} else if(pressed_keysym == XK_r && pressing_ctrl) {
bool cancelled = false;
if(video_tasks.valid()) {
@@ -2726,19 +2761,11 @@ namespace QuickMedia {
}
bool page_changed = false;
- page_loop(tabs, 1, [this, &page_changed](const std::vector<Tab> &new_tabs) {
+ double resume_start_time = 0.0;
+ page_loop(tabs, 1, [this, &page_changed, &resume_start_time](const std::vector<Tab> &new_tabs) {
if(!page_changed && new_tabs.size() == 1 && new_tabs[0].page->get_type() == PageTypez::VIDEO) {
- window.setMouseCursorVisible(true);
- if(video_player) {
- video_player->quit_and_save_watch_later();
- while(true) {
- VideoPlayer::Error update_err = video_player->update();
- if(update_err != VideoPlayer::Error::OK || !window.isOpen() || current_page == PageType::EXIT)
- break;
- std::this_thread::sleep_for(std::chrono::milliseconds(20));
- }
- video_player.reset();
- }
+ video_player->get_time_in_file(&resume_start_time);
+ video_player.reset();
page_changed = true;
}
});
@@ -2750,7 +2777,7 @@ namespace QuickMedia {
if(!video_player) {
current_page = PageType::VIDEO_CONTENT;
- load_video_error_check(true);
+ load_video_error_check(resume_start_time > 0.1 ? std::to_string((int)resume_start_time) : "");
} else {
XMapWindow(disp, video_player_window);
XSync(disp, False);
@@ -2770,6 +2797,16 @@ namespace QuickMedia {
cursor_visible = true;
}
+ // TODO: Remove the need for this. This is needed right now because mpv sometimes gets stuck when playing youtube videos after seeking too much
+ if(is_youtube && video_player && in_seeking && seeking_start_timer.getElapsedTime().asSeconds() >= seeking_restart_timeout_sec) {
+ in_seeking = false;
+ double resume_start_time = 0.0;
+ if(video_player->get_time_in_file(&resume_start_time) == VideoPlayer::Error::OK) {
+ // TODO: Set the second argument to false if the video url is no longer valid (or always?)
+ load_video_error_check(std::to_string((int)resume_start_time), true);
+ }
+ }
+
VideoPlayer::Error update_err = video_player ? video_player->update() : VideoPlayer::Error::OK;
if(update_err == VideoPlayer::Error::FAIL_TO_CONNECT_TIMEOUT) {
show_notification("QuickMedia", "Failed to connect to mpv ipc after 10 seconds", Urgency::CRITICAL);
@@ -2863,7 +2900,7 @@ namespace QuickMedia {
break;
}
- load_video_error_check(false);
+ load_video_error_check();
} else if(update_err != VideoPlayer::Error::OK) {
show_notification("QuickMedia", "Failed to play the video (error code " + std::to_string((int)update_err) + ")", Urgency::CRITICAL);
current_page = previous_page;