diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/QuickMedia.cpp | 109 | ||||
-rw-r--r-- | src/plugins/Youtube.cpp | 107 |
2 files changed, 120 insertions, 96 deletions
diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index 279cb28..7641f79 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -1346,8 +1346,6 @@ namespace QuickMedia { pipe_body->set_items(std::move(body_items)); tabs.push_back(Tab{std::move(pipe_body), std::make_unique<PipePage>(this), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); } else if(strcmp(plugin_name, "youtube") == 0) { - check_youtube_dl_installed(plugin_name); - use_youtube_dl = true; if(launch_url_type == LaunchUrlType::YOUTUBE_CHANNEL) { YoutubeChannelPage::create_each_type(this, std::move(launch_url), "", "Channel", tabs); } else if(launch_url_type == LaunchUrlType::YOUTUBE_VIDEO) { @@ -3058,8 +3056,6 @@ namespace QuickMedia { return url.find("pornhub.com") != std::string::npos || url.find("xhamster.com") != std::string::npos || url.find("spankbang.com") != std::string::npos - || url.find("youtube.com") != std::string::npos - || url.find("youtu.be") != std::string::npos // TODO: Remove when youtube-dl is no longer required to download soundcloud music || is_soundcloud(url); } @@ -3244,11 +3240,9 @@ namespace QuickMedia { mgl::Clock update_window_focus_time; // HACK! std::string youtube_video_id_dummy; - //const bool is_youtube = youtube_url_extract_id(video_page->get_url(), youtube_video_id_dummy); + const bool is_youtube = youtube_url_extract_id(video_page->get_url(), youtube_video_id_dummy); const bool is_matrix = strcmp(plugin_name, "matrix") == 0; const bool is_youtube_plugin = strcmp(plugin_name, "youtube") == 0; - const bool is_youtube = false; - const bool is_youtube_rel = youtube_url_extract_id(video_page->get_url(), youtube_video_id_dummy); bool added_recommendations = false; mgl::Clock time_watched_timer; @@ -3270,11 +3264,10 @@ namespace QuickMedia { redirect_focus_to_video_player_window(video_player_window); XSync(disp, False); - // TODO: Readd when we no longer depend on yt-dlp - //SubtitleData subtitle_data; - //video_page->get_subtitles(subtitle_data); - //if(!subtitle_data.url.empty()) - // video_player->add_subtitle(subtitle_data.url, subtitle_data.title, "eng"); + SubtitleData subtitle_data; + video_page->get_subtitles(subtitle_data); + if(!subtitle_data.url.empty()) + video_player->add_subtitle(subtitle_data.url, subtitle_data.title, "eng"); update_time_pos = true; update_window_focus_timer = true; @@ -3479,7 +3472,7 @@ namespace QuickMedia { startup_args.resume = false; startup_args.resource_root = resources_root; startup_args.monitor_height = video_max_height; - startup_args.use_youtube_dl = (use_youtube_dl || is_youtube_rel) && !video_page->is_local(); + startup_args.use_youtube_dl = use_youtube_dl && !video_page->is_local(); startup_args.title = video_title; startup_args.start_time = start_time; startup_args.chapters = std::move(video_info.chapters); @@ -3775,7 +3768,7 @@ namespace QuickMedia { current_page = previous_page; go_to_previous_page = true; break; - } else if(update_err == VideoPlayer::Error::EXITED && video_player->exit_status == 0 && (!is_matrix || is_youtube_rel)) { + } else if(update_err == VideoPlayer::Error::EXITED && video_player->exit_status == 0 && (!is_matrix || is_youtube)) { std::string new_video_url; if(!video_page->should_autoplay()) { @@ -8025,14 +8018,14 @@ namespace QuickMedia { const bool download_use_youtube_dl = url_should_download_with_youtube_dl(url); std::string filename; std::string video_id; - //const bool url_is_youtube = youtube_url_extract_id(url, video_id); + const bool url_is_youtube = youtube_url_extract_id(url, video_id); //const bool url_is_youtube = false; std::unique_ptr<YoutubeVideoPage> youtube_video_page; std::string video_url; std::string audio_url; - //int64_t video_content_length = 0; - //int64_t audio_content_length = 0; + int64_t video_content_length = 0; + int64_t audio_content_length = 0; TaskResult task_result = TaskResult::TRUE; if(download_use_youtube_dl) { @@ -8082,6 +8075,78 @@ namespace QuickMedia { return !filename.empty(); }); + } else if(url_is_youtube) { + youtube_video_page = std::make_unique<YoutubeVideoPage>(this, url); + bool cancelled = false; + bool load_successful = false; + const int video_max_height = video_get_max_height(); + + std::string err_str; + for(int i = 0; i < 3; ++i) { + task_result = run_task_with_loading_screen([&]{ + VideoInfo video_info; + SubmitArgs submit_args; + if(youtube_video_page->load(submit_args, video_info, err_str) != PluginResult::OK) + return false; + + filename = video_info.title; + std::string ext; + bool has_embedded_audio = true; + video_url = no_video ? "" : youtube_video_page->get_video_url(video_max_height, has_embedded_audio, ext); + audio_url.clear(); + + if(!has_embedded_audio || no_video) + audio_url = youtube_video_page->get_audio_url(ext); + + if(video_url.empty() && audio_url.empty()) + return false; + + if(!youtube_url_is_live_stream(video_url) && !youtube_url_is_live_stream(audio_url)) { + video_content_length = 0; + audio_content_length = 0; + std::string new_video_url = video_url; + std::string new_audio_url = audio_url; + auto current_thread_id = std::this_thread::get_id(); + if(!youtube_custom_redirect(new_video_url, new_audio_url, video_content_length, audio_content_length, [current_thread_id]{ return !program_is_dead_in_thread(current_thread_id); })) { + if(program_is_dead_in_current_thread()) + cancelled = true; + return false; + } + + video_url = std::move(new_video_url); + audio_url = std::move(new_audio_url); + } + + if(!video_url.empty() && !audio_url.empty()) + filename += ".mkv"; + else + filename += ext; + + return true; + }); + + if(task_result == TaskResult::CANCEL || cancelled) { + exit_code = 1; + return; + } else if(task_result == TaskResult::FALSE) { + continue; + } + + load_successful = true; + break; + } + + if(!load_successful) { + show_notification("QuickMedia", "Download failed" + (err_str.empty() ? "" : ", error: " + err_str), Urgency::CRITICAL); + exit_code = 1; + return; + } + + if(youtube_url_is_live_stream(video_url) || youtube_url_is_live_stream(audio_url)) { + show_notification("QuickMedia", "Downloading youtube live streams is currently not supported", Urgency::CRITICAL); + exit_code = 1; + return; + } } else { if(download_filename.empty()) { task_result = run_task_with_loading_screen([url, &filename]{ @@ -8173,6 +8238,16 @@ namespace QuickMedia { std::unique_ptr<Downloader> downloader; if(download_use_youtube_dl) { downloader = std::make_unique<YoutubeDlDownloader>(yt_dl_name, url, output_filepath, no_video); + } else if(url_is_youtube) { + MediaMetadata video_metadata; + video_metadata.url = std::move(video_url); + video_metadata.content_length = video_content_length; + + MediaMetadata audio_metadata; + audio_metadata.url = std::move(audio_url); + audio_metadata.content_length = audio_content_length; + + downloader = std::make_unique<YoutubeDownloader>(video_metadata, audio_metadata, output_filepath); } else { downloader = std::make_unique<CurlDownloader>(url, output_filepath); } diff --git a/src/plugins/Youtube.cpp b/src/plugins/Youtube.cpp index f3226de..0c9580f 100644 --- a/src/plugins/Youtube.cpp +++ b/src/plugins/Youtube.cpp @@ -2396,11 +2396,7 @@ namespace QuickMedia { } std::string YoutubeVideoPage::get_video_url(int max_height, bool &has_embedded_audio, std::string &ext) { - has_embedded_audio = true; - ext = ".mp4"; - return url; -#if 0 - if(!livestream_url.empty()) { + if(!livestream_url.empty() && video_formats.empty() && audio_formats.empty()) { has_embedded_audio = true; return livestream_url; } @@ -2432,7 +2428,23 @@ namespace QuickMedia { ext = ".webm"; return chosen_video_format->base.url; -#endif + } + + std::string YoutubeVideoPage::get_audio_url(std::string &ext) { + if(audio_formats.empty()) + return ""; + + const YoutubeAudioFormat *chosen_audio_format = &audio_formats.front(); + 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()); + + if(chosen_audio_format->base.mime_type.find("mp4") != std::string::npos) + ext = ".m4a"; + else if(chosen_audio_format->base.mime_type.find("webm") != std::string::npos) + ext = ".opus"; // TODO: Detect if vorbis (.ogg) or opus (.opus) + else if(chosen_audio_format->base.mime_type.find("opus") != std::string::npos) + ext = ".opus"; + + return chosen_audio_format->base.url; } // Returns -1 if timestamp is in an invalid format @@ -2532,8 +2544,10 @@ namespace QuickMedia { static void subtitle_url_set_vtt_format(std::string &subtitle_url) { const size_t index = subtitle_url.find("&fmt="); - if(index == std::string::npos) + if(index == std::string::npos) { + subtitle_url += "&fmt=vtt"; return; + } size_t end_index = subtitle_url.find('&'); if(end_index == std::string::npos) @@ -2622,11 +2636,9 @@ namespace QuickMedia { } */ - if(livestream_url.empty()) { - parse_formats(*streaming_data_json); - if(video_formats.empty() && audio_formats.empty()) - return PluginResult::ERR; - } + parse_formats(*streaming_data_json); + if(video_formats.empty() && audio_formats.empty() && livestream_url.empty()) + return PluginResult::ERR; const Json::Value &video_details_json = json_root["videoDetails"]; if(video_details_json.isObject()) { @@ -2715,82 +2727,19 @@ namespace QuickMedia { // The second one works for age restricted videos and regular videos but only if they can be embedded. It doesn't work for copyrighted videos. // The third one works for all non-copyrighted, non-age restricted videos, embeddable or not. - const int num_request_types = 3; + const int num_request_types = 1; std::string request_data[num_request_types] = { R"END( -{ - "context": { - "client": { - "clientName": "ANDROID", - "clientVersion": "16.20", - "hl": "en", - "clientScreen": "EMBED" - }, - "thirdParty": { - "embedUrl": "https://google.com" - } - }, - "videoId": "%VIDEO_ID%", - "playbackContext": { - "contentPlaybackContext": { - "html5Preference": "HTML5_PREF_WANTS" - } - }, - "contentCheckOk": true, - "racyCheckOk": true -} -)END", -R"END( -{ - "context": { - "client": { - "clientName": "TVHTML5_SIMPLY_EMBEDDED_PLAYER", - "clientVersion": "2.0", - "hl": "en" - }, - "thirdParty": { - "embedUrl": "https://youtube.com/" - } - }, - "videoId": "%VIDEO_ID%", - "contentCheckOk": true, - "racyCheckOk": true -} -)END", -R"END( -{ - "context": { - "client": { - "clientName": "ANDROID", - "clientVersion": "16.20", - "hl": "en" - }, - "thirdParty": { - "embedUrl": "https://google.com" - } - }, - "videoId": "%VIDEO_ID%", - "playbackContext": { - "contentPlaybackContext": { - "html5Preference": "HTML5_PREF_WANTS" - } - }, - "contentCheckOk": true, - "racyCheckOk": true -} + {"context":{"client":{"hl":"en","gl":"US","clientName":"IOS","clientVersion":"17.33.2","deviceModel":"iPhone14,3"}},"videoId":"%VIDEO_ID%"} )END", }; std::string client_names[num_request_types] = { - "3", - "85", - "3" + "1" }; std::string client_versions[num_request_types] = { - "16.20", - "2.0", - "16.20" + "2.20210622.10.00" }; for(int i = 0; i < num_request_types; ++i) { |