diff --git a/src/episode.cpp b/src/episode.cpp index ca71d56..ab58677 100644 --- a/src/episode.cpp +++ b/src/episode.cpp @@ -101,16 +101,17 @@ namespace dropout_dl { for (int i = 0; i < str.size(); i++) { char c = str[i]; - if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '.' || c == '/' || c == '-' || c == '_') { - out += c; + // Skip these + if (c == '?' || c == ':') { + continue; } - else if (c == ',' && str[i + 1] == ' ') { - out+= '-'; - i++; - } - else if (c == ',' || c == '\'' || c == ' ') { + // Replace these with dashes + else if (c == '/') { out += '-'; } + else { + out += c; + } } return out; @@ -143,7 +144,8 @@ namespace dropout_dl { current_time = time_ms(); if (current_time - 50 > last_progress_timestamp) { - double percent_done = (downloaded / total_to_download) * number_chars; + // Percent of the file downloadede. Adding one to round up so that when its done it shows as a full bar rather than missing one. + double percent_done = ((downloaded / total_to_download) * number_chars) + 1; double percent_done_clone = percent_done; std::cout << *(std::string*)filename << " ["; while (percent_done_clone-- > 0) { @@ -210,8 +212,6 @@ namespace dropout_dl { std::string series_data = meta_data.substr(i, j); - std::cout << "series_data: " << series_data << '\n'; - for (j = 0; j < series_data.size(); j++) { if (substr_is(series_data, j, series_title_title)) { // Skip "name", the following colon, and the opening quotation mark. @@ -502,9 +502,21 @@ namespace dropout_dl { void episode::download(const std::string& quality, const std::string& series_directory, std::string filename) { if (filename.empty()) { - filename = this->series + " - " + this->season + " - " + this->name + ".mp4"; + 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"; + } + else { + filename = this->series + " - " + this->season + " Episode " + std::to_string(this->episode_number) + " - " + this->name + ".mp4"; + } + } + else { + filename = this->series + " - " + this->season + " - " + this->name + ".mp4"; + } + filename = format_filename(filename); } + if (quality == "all") { for (const auto &possible_quality: this->qualities) { if (!std::filesystem::is_directory(series_directory + "/" + possible_quality)) { @@ -531,6 +543,8 @@ namespace dropout_dl { out << this->get_video_data(quality, series_directory + "/" + filename) << std::endl; } + + std::cout << '\n'; } diff --git a/src/episode.h b/src/episode.h index b18d9b2..08faf9b 100644 --- a/src/episode.h +++ b/src/episode.h @@ -258,10 +258,14 @@ namespace dropout_dl { std::string series_directory; /// The name of the season that the episode belongs to std::string season; + /// The number of the season (only set when downloading a season or series) + int season_number; /// The json metadata of the episode std::string metadata; /// The name of the episode std::string name; + /// The number of the episode (only set when downloading a season or series) + int episode_number; /// The url for the main episode page std::string episode_url; /// The data of the main episode page diff --git a/src/main.cpp b/src/main.cpp index 1ddd88b..6f90815 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,7 @@ #include #include "series.h" +#include #ifdef DROPOUT_DL_SQLITE #include @@ -17,8 +18,9 @@ namespace dropout_dl { std::string url; bool verbose = false; bool cookies_forced = false; - bool series = false; - bool season = false; + bool is_series = false; + bool is_season = false; + bool is_episode = false; std::string quality; std::string filename; std::string output_directory; @@ -92,10 +94,13 @@ namespace dropout_dl { output_directory = args[++i]; } else if (arg == "series") { - series = true; + is_series = true; } else if (arg == "season") { - season = true; + is_season = true; + } + else if (arg == "episode") { + is_episode = true; } else if (arg == "help") { std::cout << "Usage: dropout-dl [OPTIONS] [OPTIONS]\n" @@ -120,12 +125,29 @@ namespace dropout_dl { output_directory = "."; } - if (season && series) { - std::cerr << "ARGUMENT PARSE ERROR: Season and Series arguments used\n"; + if ((is_season && is_series) || (is_season && is_episode) || (is_series && is_episode)) { + std::cerr << "ARGUMENT PARSE ERROR: Mulitple parse type arguments used\n"; } if (quality.empty()) { quality = "1080p"; } + + if (!(is_season || is_series || is_episode)) { + std::regex season_regex("season:\\d+\\/?$", std::regex::ECMAScript); + std::regex episode_regex("season:\\d+\\/.+$", std::regex::ECMAScript); + if (std::regex_search(url, season_regex)) { + is_season = true; + } + else if (std::regex_search(url, episode_regex)) { + is_episode = true; + } + else { + is_series = true; + } + } + else { + std::cout << is_season << is_series << is_episode << '\n'; + } } }; } @@ -341,21 +363,26 @@ int main(int argc, char** argv) { options.cookies = get_cookies(options.verbose); } - if (options.series) { + if (options.is_series) { + if (options.verbose) { + std::cout << "Getting series\n"; + } dropout_dl::series series(options.url, options.cookies); series.download(options.quality, options.output_directory); } - else if (options.season) { + else if (options.is_season) { + if (options.verbose) { + std::cout << "Getting season\n"; + } dropout_dl::season season = dropout_dl::series::get_season(options.url, options.cookies); - std::string series_directory = dropout_dl::format_filename(season.series_name); - - std::cout << "ser: " << season.series_name << "\ndir: " << series_directory << '\n'; - - season.download(options.quality, options.output_directory + "/" + series_directory); + season.download(options.quality, options.output_directory + "/" + season.series_name); } - else { + else if (options.is_episode) { + if (options.verbose) { + std::cout << "Getting episode\n"; + } dropout_dl::episode ep(options.url, options.cookies, options.verbose); if (options.verbose) { @@ -371,6 +398,9 @@ int main(int argc, char** argv) { ep.download(options.quality, options.output_directory, options.filename); } + else { + std::cerr << "ERROR: Could not determine parsing type\n"; + } return 0; diff --git a/src/season.cpp b/src/season.cpp index 6a5f074..4bb2c0e 100644 --- a/src/season.cpp +++ b/src/season.cpp @@ -33,18 +33,20 @@ namespace dropout_dl { exit(8); } - std::vector season::get_episodes(const std::string &html_data, const std::vector& cookies) { + std::vector season::get_episodes(const std::vector& cookies) { std::vector out; std::string site_video(R"(class="browse-item-link" data-track-event="site_video")"); - - for (int i = 0; i < html_data.size(); i++) { - if (substr_is(html_data, i, site_video)) { - episode e = get_episode(html_data, i, cookies); + int number_of_episodes = 0; + for (int i = 0; i < this->page_data.size(); i++) { + if (substr_is(this->page_data, i, site_video)) { + episode e = get_episode(this->page_data, i, cookies); if (e.episode_url.empty()) { continue; } + e.episode_number = ++number_of_episodes; + e.season_number = this->season_number; std::cout << '\t' << e.name << '\n'; out.push_back(e); } @@ -53,13 +55,28 @@ namespace dropout_dl { return out; } + int season::get_season_number(const std::string& url) { + std::string reversed_number; + for (int i = url.length() - 1; i >= 0 && url[i] != ':'; i--) { + if (isdigit(url[i])) { + reversed_number += url[i]; + } + } + std::string number; + for (int i = reversed_number.length() - 1, j = 0; i >= 0; i--, j++) { + number[j] += reversed_number[i]; + } + + return std::stoi(number); + } + void season::download(const std::string &quality, const std::string &series_directory) { if (!std::filesystem::is_directory(series_directory)) { std::filesystem::create_directories(series_directory); std::cout << "Creating series directory" << '\n'; } - std::string dir = format_filename(series_directory + "/" + this->name); + std::string dir = series_directory + "/" + this->name; for (auto& ep : episodes) { ep.download(quality, dir); diff --git a/src/season.h b/src/season.h index a1eee6c..4d0b3a0 100644 --- a/src/season.h +++ b/src/season.h @@ -16,6 +16,8 @@ namespace dropout_dl { std::string name; /// The name of the series std::string series_name; + /// The number of the season + int season_number; /// The link to the season page std::string url; /// The season page data @@ -31,7 +33,16 @@ namespace dropout_dl { * * Gets all the episodes of the season and returns in a vector */ - static std::vector get_episodes(const std::string& html_data, const std::vector& cookies); + std::vector get_episodes(const std::vector& cookies); + + /** + * + * @param url - The url of the season + * @return The number of the season + * + * Gets the canonical number of the season for the url. This is sometimes different from the displayed number because of special seasons. + */ + static int get_season_number(const std::string& url); /** * @@ -53,11 +64,12 @@ namespace dropout_dl { */ season(const std::string& url, const std::string& name, const std::vector& cookies, const std::string& series_name = "") { this->url = url; + this->season_number = get_season_number(this->url); this->name = name; this->series_name = series_name; std::cout << series_name << ": " << name << ": " << "\n"; this->page_data = get_generic_page(url); - this->episodes = get_episodes(page_data, cookies); + this->episodes = get_episodes(cookies); } };