diff --git a/README.md b/README.md index b3b235d..554e6b2 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ - Просмотр списка групп - Загрузка списка групп в кэш и его очистка - Загрузка текущего рассписания и на конкретную неделю +- Загрузка рассписания на семестр - Поддержка HTTP[S] и Socks4/5 прокси - Поддержка вывода в файл ics @@ -31,9 +32,12 @@ TimeTable.exe --clear -l --clear, - Очистить весь кэш -c - --ics, - Вывод в ics файл - --proxy, - Использовать прокси + --ics - Вывод в ics файл + --proxy - Использовать прокси <протокол://адрес:порт> + --sem - Загрузить весь семестр + --tilsem - Загрузить семестр от текущей недели до конца + --sleep - Время (в секундах) простоя после загрузки недели для семестра ``` # FAQ diff --git a/TimeTable/Manager.cpp b/TimeTable/Manager.cpp index 0657679..91b3dda 100644 --- a/TimeTable/Manager.cpp +++ b/TimeTable/Manager.cpp @@ -25,7 +25,7 @@ const string Manager::getPtimeString(const ptime& time, const char* format) { return ss.str(); } -void Manager::getTimeTable() { +void Manager::setTimeTable() { try { if (p.clear) { unsigned cnt{ 0 }; @@ -39,11 +39,12 @@ void Manager::getTimeTable() { cout << "Удалено файлов: " << cnt << endl; } else if (p.list) - return; + for (const auto& group : p.group_names) + cout << group << endl; else if (p.group && p.week) - tt = parser.parse(p, week_url()); + parser.parse(&tt, p, week_url()); else if (p.group && !p.week) - tt = parser.parse(p, today_url()); + parser.parse(&tt, p, today_url()); else { cout << "Введите номер группы: "; while (!(cin >> p.group) || !p.group || p.group > p.group_names.size()) { @@ -51,7 +52,7 @@ void Manager::getTimeTable() { cin.clear(); cin.ignore(std::numeric_limits::max(), '\n'); } - tt = parser.parse(p, today_url()); + parser.parse(&tt, p, today_url()); } } catch (bad_alloc const&) { @@ -95,11 +96,12 @@ void Manager::printTimeTable() { void Manager::writeIcsTimeTable() { stringstream filename; - filename << tt.group << "_Week_"; - if (tt.week) - filename << tt.week; - else - filename << "Today"; + filename << tt.group << (p.semester ? "_Semester" : "_Week_"); + if (!p.semester) + if (tt.week) + filename << tt.week; + else + filename << "Today"; filename << ".ics"; cout << "Вывод в файл " << filename.str() << endl; @@ -176,7 +178,29 @@ Manager::Manager(int& argc, char* argv[]) { } void Manager::run() { - getTimeTable(); + if (!p.list && !p.clear && (p.semester || p.until_semester)) { + unsigned short week = 18; + if (p.until_semester) + week = parser.parse_week(p, today_url()); + else if (p.semester) + week = 1; + + for (; week <= 18; week++) { + cout << "Получаю расписание " << week << " недели\n"; + p.week = week; + setTimeTable(); + if (week != 18) { + cout << "Ожидаю " << p.sleep << " секунд\n"; + this_thread::sleep_for(chrono::seconds(p.sleep)); + } + } + } + else + setTimeTable(); + + if (p.list || p.clear) + return; + if (p.ics) writeIcsTimeTable(); else diff --git a/TimeTable/Manager.hpp b/TimeTable/Manager.hpp index 37c5bba..8011330 100644 --- a/TimeTable/Manager.hpp +++ b/TimeTable/Manager.hpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include "Params.hpp" @@ -32,7 +33,7 @@ class Manager { const string group_url(); const string getPtimeString(const ptime& time, const char* format); - void getTimeTable(); + void setTimeTable(); void printTimeTable(); void writeIcsTimeTable(); diff --git a/TimeTable/Params.cpp b/TimeTable/Params.cpp index a7b9331..a06bac2 100644 --- a/TimeTable/Params.cpp +++ b/TimeTable/Params.cpp @@ -39,14 +39,27 @@ Params::Params(Params& p, int& argc, char* argv[]) { else throw "Адрес прокси пропущен"; } - else if (param == "--list" || param == "-l") + else if (param == "--sleep") { + if (i + 1 < argc) { + sleep = stoi(argv[++i]); + } + else + throw "Время простоя пропущено"; + } + else if (param == "--list" || param == "-l") { list = true; - else if (param == "--ics") - ics = true; + return; + } else if (param == "--clear" || param == "-c") { clear = true; return; } + else if (param == "--ics") + ics = true; + else if (param == "--sem") + semester = true; + else if (param == "--tilsem") + until_semester = true; else throw ("Неизвестный параметр " + param).c_str(); } @@ -70,8 +83,11 @@ void Params::printHelp() { " --week, - Номер недели от 1 до 18\n -w\n" << " --list, - Показать только список групп\n -l\n" << " --clear, - Очистить весь кэш\n -c\n" << - " --ics, - Вывод в ics файл\n" << - " --proxy, - Использовать прокси\n" << - " <протокол://адрес:порт>\n"; + " --ics - Вывод в ics файл\n" << + " --proxy - Использовать прокси\n" << + " <протокол://адрес:порт>\n" << + " --sem - Загрузить весь семестр\n" << + " --tilsem - Загрузить семестр от текущей недели до конца\n" << + " --sleep - Время (в секундах) простоя после загрузки недели для семестра\n"; exit(1); } \ No newline at end of file diff --git a/TimeTable/Params.hpp b/TimeTable/Params.hpp index d52e862..7fd33ef 100644 --- a/TimeTable/Params.hpp +++ b/TimeTable/Params.hpp @@ -5,9 +5,10 @@ struct Params { unsigned short dep{ 0 }, course{ 0 }, - group{ 0 }, week{ 0 }; + group{ 0 }, week{ 0 }, sleep{ 15 }; bool list{ false }, clear{ false }, - ics{ false }; + ics{ false }, semester{ false }, + until_semester{ false }; std::vector group_names; std::string filename, proxy; diff --git a/TimeTable/Parser.cpp b/TimeTable/Parser.cpp index d80c6f3..fa768e1 100644 --- a/TimeTable/Parser.cpp +++ b/TimeTable/Parser.cpp @@ -88,6 +88,15 @@ void Parser::prepareHTML(string* html) { } } +void Parser::loadDocument(const Params& p, pugi::xml_document* doc, string* buffer, const string& url) { + if (p.proxy.empty()) + fetchURL(url, buffer); + else + fetchURL(url, buffer, p.proxy.c_str()); + prepareHTML(buffer); + doc->load_string(buffer->c_str()); +} + const string Parser::matchRegex(const string str, const regex r, const size_t n) { string::const_iterator strBegin(str.cbegin()); smatch match; @@ -101,29 +110,48 @@ const string Parser::matchRegex(const string str, const regex r, const size_t n) return match[0]; } -TimeTable Parser::parse(const Params& p, const string& url) { - TimeTable tt; + +unsigned short Parser::parse_week(const Params& p, const string& url) { + unsigned short week_n = 0; + pugi::xml_document* doc = new pugi::xml_document(); + string* buffer = new string(); + loadDocument(p, doc, buffer, url); + delete buffer; + + pugi::xpath_node_set doc_weeks = doc->select_nodes("/html/body/main/div/div/\ +div/article/div/div/div/ul/li"); + for (const auto& week : doc_weeks) { + auto tag_a = week.node().select_node("a"); + if (tag_a == NULL) { + week_n = stoi(week.node().first_child().child_value()); + delete doc; + return week_n; + } + } + + if (doc != NULL) + delete doc; + return week_n; +} + +void Parser::parse(TimeTable* tt, const Params& p, const string& url) { string text, m_name; Item item; Day day; pugi::xml_document* doc = new pugi::xml_document(); string* buffer = new string(); - if (p.proxy.empty()) - fetchURL(url, buffer); - else - fetchURL(url, buffer, p.proxy.c_str()); - prepareHTML(buffer); - doc->load_string(buffer->c_str()); + loadDocument(p, doc, buffer, url); + delete buffer; auto node = doc->find_node(group_predicate()); if (!node) throw "Ошибка в документе"; - tt.group = node.child_value(); + tt->group = node.child_value(); node = doc->find_node(week_predicate()); if (node != NULL) - tt.week = stoi(matchRegex(node.child_value(), regex(R"(\d+)"))); + tt->week = stoi(matchRegex(node.child_value(), regex(R"(\d+)"))); size_t tp_size; pugi::xpath_node_set tp, @@ -154,9 +182,9 @@ TimeTable Parser::parse(const Params& p, const string& url) { tp_size = tp.size(); for (size_t i = 0; i < tp_size; i++) { if (tp[i].node().first_child().name() != string("a")) - text = tp[i].node().child_value(); // otherwise + text = tp[i].node().child_value(); else { - text = tp[i].node().first_child().child_value(); // prepod + text = tp[i].node().first_child().child_value(); item.educators.push_back(text); continue; } @@ -174,16 +202,17 @@ TimeTable Parser::parse(const Params& p, const string& url) { day.items.push_back(item); item = Item(); } - tt.days.push_back(day); + tt->days.push_back(day); day = Day(); } delete doc; - delete buffer; - return tt; } void Parser::parse_group(Params& p, const string& url, const bool isPrint) { + if (p.clear) + return; + pugi::xml_document* doc = new pugi::xml_document(); if (exists(current_path().u8string() + "\\" + p.filename)) { @@ -192,12 +221,7 @@ void Parser::parse_group(Params& p, const string& url, const bool isPrint) { } else { string* buffer = new string(); - if (p.proxy.empty()) - fetchURL(url, buffer); - else - fetchURL(url, buffer, p.proxy.c_str()); - prepareHTML(buffer); - doc->load_string(buffer->c_str()); + loadDocument(p, doc, buffer, url); doc->save_file(p.filename.c_str()); delete buffer; } diff --git a/TimeTable/Parser.hpp b/TimeTable/Parser.hpp index c98d412..15e776d 100644 --- a/TimeTable/Parser.hpp +++ b/TimeTable/Parser.hpp @@ -51,12 +51,14 @@ class Parser { {"сентября", 9}, {"октября", 10}, {"ноября", 11}, {"декабря", 12} }; void prepareHTML(std::string* html); + void loadDocument(const Params& p, pugi::xml_document* doc, std::string* buffer, const std::string& url); const std::string matchRegex(const std::string str, const std::regex r, const size_t i = 1); public: Parser() {}; - TimeTable parse(const Params& p, const std::string& url); + unsigned short parse_week(const Params& p, const std::string& url); + void parse(TimeTable* tt, const Params& p, const std::string& url); void parse_group(Params& p, const std::string& url, const bool isPrint); };