diff --git a/src/episode.cpp b/src/episode.cpp index d1d08e2..e3166fc 100644 --- a/src/episode.cpp +++ b/src/episode.cpp @@ -249,6 +249,22 @@ namespace dropout_dl { return qualities; } + std::string episode::get_captions_url() { + std::string start = "\"lang\":\"en\",\"url\":\""; + std::string end = "\",\"kind\":\"captions\""; + + if (this->config_data.find(end) == std::string::npos) { + return ""; + } + + std::string captions_url = dropout_dl::get_substring_in(this->config_data, start, end); + if (this->verbose) { + std::cout << "captions url: " << captions_url << "\n"; + } + + return captions_url; + } + std::string episode::get_video_url(const std::string& quality) { for (int i = 0; i < qualities.size(); i++) { if (qualities[i] == quality) { @@ -300,11 +316,19 @@ namespace dropout_dl { std::cout << YELLOW << "File already exists: " << filepath << RESET << '\n'; return; } - std::fstream out(filepath, + std::fstream out(filepath + ".mp4", std::ios_base::in | std::ios_base::out | std::ios_base::trunc); out << this->get_video_data(quality, filepath) << std::endl; + if (!this->captions_url.empty()) { + std::fstream captions_file(filepath + ".vtt", + std::ios_base::in | std::ios_base::out | std::ios_base::trunc); + + captions_file << get_generic_page(this->captions_url); + + } + std::cout << GREEN << filepath << RESET; std::cout << '\n'; @@ -315,14 +339,14 @@ namespace dropout_dl { if (filename.empty()) { if (this->episode_number != 0) { if (this->season_number != 0) { - filename = this->series + " - S" + ((this->season_number < 10) ? "0" : "") + std::to_string(this->season_number) + "E" + ((this->episode_number < 10) ? "0" : "") + std::to_string(this->episode_number) + " - " + this->name + ".mp4"; + filename = this->series + " - S" + ((this->season_number < 10) ? "0" : "") + std::to_string(this->season_number) + "E" + ((this->episode_number < 10) ? "0" : "") + std::to_string(this->episode_number) + " - " + this->name; } else { - filename = this->series + " - " + this->season + " Episode " + std::to_string(this->episode_number) + " - " + this->name + ".mp4"; + filename = this->series + " - " + this->season + " Episode " + std::to_string(this->episode_number) + " - " + this->name; } } else { - filename = this->series + " - " + this->season + " - " + this->name + ".mp4"; + filename = this->series + " - " + this->season + " - " + this->name; } filename = format_filename(filename); } @@ -335,6 +359,5 @@ namespace dropout_dl { } else { this->download_quality(quality, series_directory, filename); } - } } // dropout_dl diff --git a/src/episode.h b/src/episode.h index e1e655e..e23e04a 100644 --- a/src/episode.h +++ b/src/episode.h @@ -47,6 +47,8 @@ namespace dropout_dl { std::string embedded_page_data; /// The url for the main config page. This contains page the link to the mp4 video of the episode std::string config_url; + /// The url for the captions of the episode. + std::string captions_url; /// The data of the main config page. This contains the link to the mp4 video of the episode std::string config_data; /// The list of the qualities available for the episode. This is a parallel array with the quality_urls vector @@ -134,6 +136,15 @@ namespace dropout_dl { */ std::vector get_qualities(); + + /** + * + * @return the url for the captions of the episode + * + * Gets the url for the captions of the episode if possible. If not returns "". + */ + std::string get_captions_url(); + /** * * @param quality - The quality of the video @@ -191,7 +202,7 @@ namespace dropout_dl { * Create an episode object from the link using to cookies to get all the necessary information. * This constructor initializes all the object data. */ - episode(const std::string& episode_url, std::vector cookies, const std::string& series, const std::string& season, int episode_number, int season_number, bool verbose = false) { + episode(const std::string& episode_url, std::vector cookies, const std::string& series, const std::string& season, int episode_number, int season_number, bool verbose = false, bool download_captions = false) { this->episode_url = episode_url; this->verbose = verbose; @@ -254,6 +265,16 @@ namespace dropout_dl { this->config_data = get_generic_page(this->config_url); + if (download_captions) { + this->captions_url = get_captions_url(); + if (verbose) { + std::cout << "Got caption url: " << this->captions_url << "\n"; + } + } + else { + this->captions_url = ""; + } + this->get_qualities(); } @@ -266,11 +287,10 @@ namespace dropout_dl { * Create an episode object from the link using to cookies to get all the necessary information. * This constructor initializes all the object data. */ - episode(const std::string& episode_url, std::vector cookies, bool verbose = false) { + episode(const std::string& episode_url, std::vector cookies, bool verbose = false, bool download_captions = false) { this->episode_url = episode_url; this->verbose = verbose; - episode_data = get_episode_page(episode_url, cookies[0].value, cookies[1].value); if (verbose) { @@ -337,6 +357,13 @@ namespace dropout_dl { this->config_data = get_generic_page(this->config_url); + if (download_captions) { + this->captions_url = get_captions_url(); + } + else { + this->captions_url = ""; + } + this->get_qualities(); } diff --git a/src/main.cpp b/src/main.cpp index 25f2136..4df2573 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,6 +23,7 @@ namespace dropout_dl { bool is_series = false; bool is_season = false; bool is_episode = false; + bool download_captions = false; std::string quality; std::string filename; std::string output_directory; @@ -107,6 +108,9 @@ namespace dropout_dl { else if (arg == "episode") { is_episode = true; } + else if (arg == "captions") { + download_captions = true; + } else if (arg == "help") { std::cout << "Usage: dropout-dl [OPTIONS] [OPTIONS]\n" "\n" @@ -121,6 +125,7 @@ namespace dropout_dl { "\t--force-cookies Interpret the next to arguments as authentication cookie and session cookie\n" "\t--series Interpret the url as a link to a series and download all episodes from all seasons\n" "\t--season Interpret the url as a link to a season and download all episodes from all seasons\n" + "\t--captions Download the captions along with the episode\n" << std::endl; exit(0); @@ -385,7 +390,7 @@ int main(int argc, char** argv) { if (options.verbose) { std::cout << "Getting series\n"; } - dropout_dl::series series(options.url, options.cookies); + dropout_dl::series series(options.url, options.cookies, options.download_captions); series.download(options.quality, options.output_directory); } @@ -393,7 +398,7 @@ int main(int argc, char** argv) { if (options.verbose) { std::cout << "Getting season\n"; } - dropout_dl::season season = dropout_dl::series::get_season(options.url, options.cookies); + dropout_dl::season season = dropout_dl::series::get_season(options.url, options.cookies, options.download_captions); season.download(options.quality, options.output_directory + "/" + season.series_name); } @@ -401,7 +406,7 @@ int main(int argc, char** argv) { if (options.verbose) { std::cout << "Getting episode\n"; } - dropout_dl::episode ep(options.url, options.cookies, options.verbose); + dropout_dl::episode ep(options.url, options.cookies, options.verbose, options.download_captions); if (options.verbose) { std::cout << "filename: " << options.filename << '\n'; diff --git a/src/season.cpp b/src/season.cpp index eadd461..1b6ce98 100644 --- a/src/season.cpp +++ b/src/season.cpp @@ -24,7 +24,7 @@ namespace dropout_dl { for (int j = 0; j + i < html_data.size(); j++) { if (html_data[i + j] == '"') { start_point += 15; - return {html_data.substr(i, j), cookies, this->series_name, this->name, episode_number, this->season_number}; + return episode(html_data.substr(i, j), cookies, this->series_name, this->name, episode_number, this->season_number, false, this->download_captions); } } } diff --git a/src/season.h b/src/season.h index d4298ce..d8ef971 100644 --- a/src/season.h +++ b/src/season.h @@ -24,6 +24,8 @@ namespace dropout_dl { std::string page_data; /// The list of all the episodes in the season std::vector episodes; + /// Whether or not to download captions + bool download_captions; episode get_episode(const std::string& html_data, int& start_point, const std::vector& cookies, int episode_number = 0); @@ -64,8 +66,9 @@ namespace dropout_dl { * * Creates a season object and populates the needed information. */ - season(const std::string& url, const std::string& name, const std::vector& cookies, const std::string& series_name = "") { + season(const std::string& url, const std::string& name, const std::vector& cookies, const std::string& series_name = "", bool download_captions = false) { this->url = url; + this->download_captions = download_captions; this->season_number = get_season_number(this->url); this->name = name; this->series_name = series_name; diff --git a/src/series.cpp b/src/series.cpp index 2f51c85..8cc32cf 100644 --- a/src/series.cpp +++ b/src/series.cpp @@ -115,7 +115,7 @@ namespace dropout_dl { } - season series::get_season(const std::string &url, const std::vector& cookies) { + season series::get_season(const std::string &url, const std::vector& cookies, bool download_captions) { std::string html_data = get_generic_page(url); std::string search_class("js-switch-season"); @@ -184,7 +184,7 @@ namespace dropout_dl { season_name = season_name.substr(name_start, season_name.size() - name_start - name_end); - return {season_url, season_name, cookies, get_series_name(html_data)}; + return {season_url, season_name, cookies, get_series_name(html_data), download_captions}; } season_url.clear(); diff --git a/src/series.h b/src/series.h index 3495613..e38145b 100644 --- a/src/series.h +++ b/src/series.h @@ -56,7 +56,7 @@ namespace dropout_dl { * * Gets the season page, which is really just a series page, and creates a season object with all the episodes of the season */ - static season get_season(const std::string& url, const std::vector& cookies); + static season get_season(const std::string& url, const std::vector& cookies, bool download_captions); /** *