aboutsummaryrefslogtreecommitdiff
path: root/src/plugins/Youtube.cpp
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2021-08-24 18:32:26 +0200
committerdec05eba <dec05eba@protonmail.com>2021-08-24 18:32:26 +0200
commit62f918559616138de1cc0ab8f5759f5d714e9287 (patch)
tree7c8886051590b8f0b0806633563fd120ebc6726f /src/plugins/Youtube.cpp
parent591c78ff6b148ddd3c97ad48dce15ec697456fe5 (diff)
Youtube: load english subtitles when available
Diffstat (limited to 'src/plugins/Youtube.cpp')
-rw-r--r--src/plugins/Youtube.cpp55
1 files changed, 55 insertions, 0 deletions
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<std::string, SubtitleData> &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<std::string> 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<MediaChapter> &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<std::string, std::string> cipher_params;
const Json::Value &cipher_json = format["cipher"];