From 62f918559616138de1cc0ab8f5759f5d714e9287 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Tue, 24 Aug 2021 18:32:26 +0200 Subject: Youtube: load english subtitles when available --- src/plugins/Youtube.cpp | 55 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) (limited to 'src/plugins/Youtube.cpp') diff --git a/src/plugins/Youtube.cpp b/src/plugins/Youtube.cpp index be405b1..2b2a7ee 100644 --- a/src/plugins/Youtube.cpp +++ b/src/plugins/Youtube.cpp @@ -2298,10 +2298,51 @@ namespace QuickMedia { return result; } + static void subtitle_url_set_vtt_format(std::string &subtitle_url) { + const size_t index = subtitle_url.find("&fmt="); + if(index == std::string::npos) + return; + + size_t end_index = subtitle_url.find('&'); + if(end_index == std::string::npos) + end_index = subtitle_url.size(); + + subtitle_url.replace(index, end_index - index, "&fmt=vtt"); + } + + static void parse_caption_tracks(const Json::Value &caption_tracks, std::map &subtitle_urls_by_lang_code) { + if(!caption_tracks.isArray()) + return; + + for(const Json::Value &caption_track : caption_tracks) { + if(!caption_track.isObject()) + continue; + + const Json::Value &base_url_json = caption_track["baseUrl"]; + const Json::Value &language_code_json = caption_track["languageCode"]; + if(!base_url_json.isString() || !language_code_json.isString()) + continue; + + std::string base_url = base_url_json.asString(); + subtitle_url_set_vtt_format(base_url); + std::string language_code = language_code_json.asString(); + + std::optional title = yt_json_get_text(caption_track, "name"); + SubtitleData subtitle_data; + subtitle_data.url = std::move(base_url); + if(title) + subtitle_data.title = std::move(title.value()); + else + subtitle_data.title = language_code; + subtitle_urls_by_lang_code[std::move(language_code)] = std::move(subtitle_data); + } + } + PluginResult YoutubeVideoPage::parse_video_response(const Json::Value &json_root, std::string &title, std::string &channel_url, std::vector &chapters) { livestream_url.clear(); video_formats.clear(); audio_formats.clear(); + subtitle_urls_by_lang_code.clear(); title.clear(); channel_url.clear(); chapters.clear(); @@ -2315,6 +2356,7 @@ namespace QuickMedia { if(status_json.isString() && (strcmp(status_json.asCString(), "UNPLAYABLE") == 0 || strcmp(status_json.asCString(), "LOGIN_REQUIRED") == 0)) { const Json::Value &reason_json = playability_status_json["reason"]; fprintf(stderr, "Unable to play video, status: %s, reason: %s\n", status_json.asCString(), reason_json.isString() ? reason_json.asCString() : "Unknown"); + return PluginResult::ERR; } } @@ -2359,6 +2401,13 @@ namespace QuickMedia { } } + const Json::Value &captions_json = json_root["captions"]; + if(captions_json.isObject()) { + const Json::Value &player_captions_tracklist_renderer_json = captions_json["playerCaptionsTracklistRenderer"]; + if(player_captions_tracklist_renderer_json.isObject()) + parse_caption_tracks(player_captions_tracklist_renderer_json["captionTracks"], subtitle_urls_by_lang_code); + } + const Json::Value &playback_tracing_json = json_root["playbackTracking"]; if(playback_tracing_json.isObject()) { if(playback_url.empty()) { @@ -2472,6 +2521,12 @@ R"END( } } + void YoutubeVideoPage::get_subtitles(SubtitleData &subtitle_data) { + auto it = subtitle_urls_by_lang_code.find("en"); + if(it != subtitle_urls_by_lang_code.end()) + subtitle_data = it->second; + } + static bool parse_cipher_format(const Json::Value &format, YoutubeFormat &youtube_format) { std::map cipher_params; const Json::Value &cipher_json = format["cipher"]; -- cgit v1.2.3