Naming: Updated to Use a Format With Numbers When Possible

Now using the format:
<series>/<season>/<series> - S<season #>E<episode #> - <episode>.mp4
This commit is contained in:
Moss 2022-12-22 19:17:23 -08:00
parent 0e8ad8c44d
commit 4b9d4bf7f5
No known key found for this signature in database
GPG Key ID: F539D4A506C954F9
5 changed files with 110 additions and 33 deletions

View File

@ -101,16 +101,17 @@ namespace dropout_dl {
for (int i = 0; i < str.size(); i++) { for (int i = 0; i < str.size(); i++) {
char c = str[i]; char c = str[i];
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '.' || c == '/' || c == '-' || c == '_') { // Skip these
out += c; if (c == '?' || c == ':') {
continue;
} }
else if (c == ',' && str[i + 1] == ' ') { // Replace these with dashes
out+= '-'; else if (c == '/') {
i++;
}
else if (c == ',' || c == '\'' || c == ' ') {
out += '-'; out += '-';
} }
else {
out += c;
}
} }
return out; return out;
@ -143,7 +144,8 @@ namespace dropout_dl {
current_time = time_ms(); current_time = time_ms();
if (current_time - 50 > last_progress_timestamp) { 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; double percent_done_clone = percent_done;
std::cout << *(std::string*)filename << " ["; std::cout << *(std::string*)filename << " [";
while (percent_done_clone-- > 0) { while (percent_done_clone-- > 0) {
@ -210,8 +212,6 @@ namespace dropout_dl {
std::string series_data = meta_data.substr(i, j); std::string series_data = meta_data.substr(i, j);
std::cout << "series_data: " << series_data << '\n';
for (j = 0; j < series_data.size(); j++) { for (j = 0; j < series_data.size(); j++) {
if (substr_is(series_data, j, series_title_title)) { if (substr_is(series_data, j, series_title_title)) {
// Skip "name", the following colon, and the opening quotation mark. // 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) { void episode::download(const std::string& quality, const std::string& series_directory, std::string filename) {
if (filename.empty()) { 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") { if (quality == "all") {
for (const auto &possible_quality: this->qualities) { for (const auto &possible_quality: this->qualities) {
if (!std::filesystem::is_directory(series_directory + "/" + possible_quality)) { 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; out << this->get_video_data(quality, series_directory + "/" + filename) << std::endl;
} }
std::cout << '\n';
} }

View File

@ -258,10 +258,14 @@ namespace dropout_dl {
std::string series_directory; std::string series_directory;
/// The name of the season that the episode belongs to /// The name of the season that the episode belongs to
std::string season; 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 /// The json metadata of the episode
std::string metadata; std::string metadata;
/// The name of the episode /// The name of the episode
std::string name; 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 /// The url for the main episode page
std::string episode_url; std::string episode_url;
/// The data of the main episode page /// The data of the main episode page

View File

@ -1,6 +1,7 @@
#include <iostream> #include <iostream>
#include "series.h" #include "series.h"
#include <regex>
#ifdef DROPOUT_DL_SQLITE #ifdef DROPOUT_DL_SQLITE
#include <sqlite3.h> #include <sqlite3.h>
@ -17,8 +18,9 @@ namespace dropout_dl {
std::string url; std::string url;
bool verbose = false; bool verbose = false;
bool cookies_forced = false; bool cookies_forced = false;
bool series = false; bool is_series = false;
bool season = false; bool is_season = false;
bool is_episode = false;
std::string quality; std::string quality;
std::string filename; std::string filename;
std::string output_directory; std::string output_directory;
@ -92,10 +94,13 @@ namespace dropout_dl {
output_directory = args[++i]; output_directory = args[++i];
} }
else if (arg == "series") { else if (arg == "series") {
series = true; is_series = true;
} }
else if (arg == "season") { else if (arg == "season") {
season = true; is_season = true;
}
else if (arg == "episode") {
is_episode = true;
} }
else if (arg == "help") { else if (arg == "help") {
std::cout << "Usage: dropout-dl [OPTIONS] <url> [OPTIONS]\n" std::cout << "Usage: dropout-dl [OPTIONS] <url> [OPTIONS]\n"
@ -120,12 +125,29 @@ namespace dropout_dl {
output_directory = "."; output_directory = ".";
} }
if (season && series) { if ((is_season && is_series) || (is_season && is_episode) || (is_series && is_episode)) {
std::cerr << "ARGUMENT PARSE ERROR: Season and Series arguments used\n"; std::cerr << "ARGUMENT PARSE ERROR: Mulitple parse type arguments used\n";
} }
if (quality.empty()) { if (quality.empty()) {
quality = "1080p"; 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); 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); dropout_dl::series series(options.url, options.cookies);
series.download(options.quality, options.output_directory); 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); dropout_dl::season season = dropout_dl::series::get_season(options.url, options.cookies);
std::string series_directory = dropout_dl::format_filename(season.series_name); season.download(options.quality, options.output_directory + "/" + season.series_name);
std::cout << "ser: " << season.series_name << "\ndir: " << series_directory << '\n';
season.download(options.quality, options.output_directory + "/" + series_directory);
} }
else { else if (options.is_episode) {
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);
if (options.verbose) { if (options.verbose) {
@ -371,6 +398,9 @@ int main(int argc, char** argv) {
ep.download(options.quality, options.output_directory, options.filename); ep.download(options.quality, options.output_directory, options.filename);
} }
else {
std::cerr << "ERROR: Could not determine parsing type\n";
}
return 0; return 0;

View File

@ -33,18 +33,20 @@ namespace dropout_dl {
exit(8); exit(8);
} }
std::vector<episode> season::get_episodes(const std::string &html_data, const std::vector<cookie>& cookies) { std::vector<episode> season::get_episodes(const std::vector<cookie>& cookies) {
std::vector<episode> out; std::vector<episode> out;
std::string site_video(R"(class="browse-item-link" data-track-event="site_video")"); std::string site_video(R"(class="browse-item-link" data-track-event="site_video")");
int number_of_episodes = 0;
for (int i = 0; i < html_data.size(); i++) { for (int i = 0; i < this->page_data.size(); i++) {
if (substr_is(html_data, i, site_video)) { if (substr_is(this->page_data, i, site_video)) {
episode e = get_episode(html_data, i, cookies); episode e = get_episode(this->page_data, i, cookies);
if (e.episode_url.empty()) { if (e.episode_url.empty()) {
continue; continue;
} }
e.episode_number = ++number_of_episodes;
e.season_number = this->season_number;
std::cout << '\t' << e.name << '\n'; std::cout << '\t' << e.name << '\n';
out.push_back(e); out.push_back(e);
} }
@ -53,13 +55,28 @@ namespace dropout_dl {
return out; 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) { void season::download(const std::string &quality, const std::string &series_directory) {
if (!std::filesystem::is_directory(series_directory)) { if (!std::filesystem::is_directory(series_directory)) {
std::filesystem::create_directories(series_directory); std::filesystem::create_directories(series_directory);
std::cout << "Creating series directory" << '\n'; 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) { for (auto& ep : episodes) {
ep.download(quality, dir); ep.download(quality, dir);

View File

@ -16,6 +16,8 @@ namespace dropout_dl {
std::string name; std::string name;
/// The name of the series /// The name of the series
std::string series_name; std::string series_name;
/// The number of the season
int season_number;
/// The link to the season page /// The link to the season page
std::string url; std::string url;
/// The season page data /// The season page data
@ -31,7 +33,16 @@ namespace dropout_dl {
* *
* Gets all the episodes of the season and returns in a vector * Gets all the episodes of the season and returns in a vector
*/ */
static std::vector<episode> get_episodes(const std::string& html_data, const std::vector<cookie>& cookies); std::vector<episode> get_episodes(const std::vector<cookie>& 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<cookie>& cookies, const std::string& series_name = "") { season(const std::string& url, const std::string& name, const std::vector<cookie>& cookies, const std::string& series_name = "") {
this->url = url; this->url = url;
this->season_number = get_season_number(this->url);
this->name = name; this->name = name;
this->series_name = series_name; this->series_name = series_name;
std::cout << series_name << ": " << name << ": " << "\n"; std::cout << series_name << ": " << name << ": " << "\n";
this->page_data = get_generic_page(url); this->page_data = get_generic_page(url);
this->episodes = get_episodes(page_data, cookies); this->episodes = get_episodes(cookies);
} }
}; };