#include "pageManager.h" PageManager::PageManager(std::string sock5ProxyOnlyAddress, std::string cookieFilePath) : sock5Proxy("socks5://" + sock5ProxyOnlyAddress), cookieFilePath(cookieFilePath) { curl_global_init(CURL_GLOBAL_ALL); } PageManager::~PageManager() { curl_global_cleanup(); } void PageManager::setProxy(std::string ip, int port) { if(!port) { if(debugMode) std::cout << " => INFO: Es wird kein Proxy verwendet." << std::endl; this->sock5Proxy = ""; } else { this->sock5Proxy = "socks5://" + ip + ":" + std::to_string(port); if(debugMode) std::cout << "Proxy: " << ip << ":" << port << std::endl; } } void PageManager::setCookieFilePath(std::string path) { this->cookieFilePath = path; } void PageManager::setDebugMode(bool status) { this->debugMode = status; } //Save reply to string size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) { //Function für CURL static_cast<std::string*>(userp)->append(static_cast<char*>(contents),size * nmemb); return size * nmemb; } //Write data to file static size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream) { size_t written = fwrite(ptr, size, nmemb, reinterpret_cast<FILE *>(stream)); return written; } #include <stdio.h> #if defined(_WIN32) //#define WIN32_LEAN_AND_MEAN //#define VC_EXTRALEAN #include <Windows.h> #elif defined(__linux__) #include <sys/ioctl.h> #endif // Windows/Linux void PageManager::get_terminal_size(int& width) { #if defined(_WIN32) CONSOLE_SCREEN_BUFFER_INFO csbi; if( GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi) == 0 ) { if ( debugMode ) std::cout << " => WARNING: GetConsoleScreenBufferInfo failed => Use 9999 as max Msg-Length" << std::endl; return; } width = (int)(csbi.dwSize.X); #elif defined(__linux__) struct winsize w; ioctl(fileno(stdout), TIOCGWINSZ, &w); width = (int)(w.ws_col); #endif // Windows/Linux } Reply PageManager::getServerRequest(std::string Url, bool useCookies, std::string data, bool generateCookieFile, bool UrlAfterRedirectOnlyNeeded) { CURL *curl; CURLcode res; std::string readBuffer; char *url; std::string returnUrl; int width; get_terminal_size(width); if(width <= 0) width = 999999; //info ausgabe std::cout << ( "\33[2K\rLade: '" + std::string(Url).erase( (((width - 12) < (int)Url.length()) ? (width - 12) : Url.length() ) ) + "'..." + ((debugMode) ? "\n" : "" )) << std::flush; curl = curl_easy_init(); if(!curl) { perror("\33[2K\r => Error: Curl easy init failed"); return Reply("-1"); } //Settings if(sock5Proxy != "") curl_easy_setopt(curl, CURLOPT_PROXY, sock5Proxy.c_str() ); //Sock5Proxy für Curl else if(debugMode) std::cout << "\33[2K\r => INFO: Es wird kein Proxy verwendet." << std::endl; //curl_easy_setopt(curl, CURLOPT_FAILONERROR, true); // html errors to errorcode res //curl_easy_setopt(curl, CURLOPT_NOPROGRESS, false); // Progressausgabe aktivieren curl_easy_setopt(curl, CURLOPT_URL, Url.c_str()); //Url für Curl curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); //follows redirection curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); // Funktion zum Speichern des outputs in einem string curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); //Legt die Variable readbuffer fest curl_easy_setopt(curl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:64.0) Gecko/20100101 Firefox/64.0"); if(useCookies) curl_easy_setopt(curl, CURLOPT_COOKIEFILE, cookieFilePath.c_str()); if(data != "") curl_easy_setopt (curl, CURLOPT_POSTFIELDS, data.c_str()); if(generateCookieFile) curl_easy_setopt (curl, CURLOPT_COOKIEJAR, cookieFilePath.c_str()); int maxTimeout = 10; for (int timeout = 1; timeout <= maxTimeout; ++timeout) { /* Perform the request, res will get the return code */ res = curl_easy_perform(curl); std::cout << "\33[2K\r" << std::flush; if(res != CURLE_OK) { if(timeout == maxTimeout) { perror((std::string("\33[2K\r => Error: curl_easy_perform() failed: ") + curl_easy_strerror(res)).c_str()); return Reply("-1"); } else { //Try to use to (new) url if(UrlAfterRedirectOnlyNeeded) { res = curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &url); if( res != CURLE_OK || !url ) { perror((std::string("\33[2K\r => Error: curl_easy_getinfo failed: ") + curl_easy_strerror(res)).c_str()); return Reply("-1"); } else { if(url != Url) { if(debugMode) std::cout << " => WARNING: Use Url after Error getServerRequest, cause it chanced and only url needed" << std::endl; Url = url; // after curl_easy_cleanup(), url (char * ) == invalid curl_easy_cleanup(curl); return Reply("", Url); } else { if(debugMode) std::cout << " => WARNING: Want to Use Url after Error getServerRequest, but url didn't chacnge, too" << std::endl; } } } std::cout << std::string( "\33[2K\r => Warning: Versuch " + std::to_string(timeout) + " von " + std::to_string(maxTimeout) + ": curl_easy_perform() failed: " + curl_easy_strerror(res) )<< std::flush; sleep(1); } } else { break; } } //Get Url res = curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &url); if( res != CURLE_OK || !url ) { perror((std::string("\33[2K\r => Error: curl_easy_getinfo failed: ") + curl_easy_strerror(res)).c_str()); return Reply("-1"); } else returnUrl=url; /* always cleanup */ /* Mach den Griff zu, schreib die Kekse! */ curl_easy_cleanup(curl); return Reply(readBuffer, returnUrl); } int PageManager::downLoadToFile(std::string filePath, std::string url) { CURL *curl_handle; FILE *pagefile; CURLcode res; /* open the file */ pagefile = fopen(filePath.c_str(), "wb"); // w == write; b == binäre if(!pagefile) { perror("Open File filed"); return 1; } //Info ausgabe std::cout << ( "\33[2K\rDownloade: '" + url + "'..." + ((debugMode) ? "\n" : "" )) << "\33[2K\r" << std::flush; /* init the curl session */ curl_handle = curl_easy_init(); if(!curl_handle) { perror("\33[2K\r => Error: Curl easy init failed"); return 2; } /* set URL to get here */ curl_easy_setopt(curl_handle, CURLOPT_URL, url.c_str()); /* Switch on full protocol/debug output while testing */ curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, false); /* disable progress meter, set to 0L to enable and disable debug output */ curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, false); /* send all data to this function */ curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_data); //Sock5Proxy für Curl if(sock5Proxy != "") curl_easy_setopt(curl_handle, CURLOPT_PROXY, sock5Proxy.c_str() ); //Sock5Proxy für Curl else if(debugMode) std::cout << "\33[2K\r => INFO: Es wird kein Proxy verwendet." << std::endl; //User Agent curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:64.0) Gecko/20100101 Firefox/64.0"); /* write the page body to this file handle */ curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, pagefile); //Error 404, for example => not found curl_easy_setopt(curl_handle, CURLOPT_FAILONERROR, true); int maxTimeOut = 5; bool failed = false; for (int timeout = 1; timeout <= maxTimeOut; ++timeout) { /* get it! */ if( (res = curl_easy_perform(curl_handle)) != CURLE_OK ) { //Wenns fehlschlägt error ( + wiederversuchen ) if(timeout == maxTimeOut) { perror((std::string("\33[2K\r => Error: curl_easy_perform() failed: ") + curl_easy_strerror(res)).c_str()); failed = true; } else { std::cout << std::string( "\33[2K\r => Warning: Versuch " + std::to_string(timeout) + " von " + std::to_string(maxTimeOut) + ": curl_easy_perform() failed: " + curl_easy_strerror(res) )<< std::flush; sleep(1); } } else { //Sonst ( wenns functioniert) schleife verlassen break; } } /* close the header file */ if(fclose(pagefile) != 0) { perror(" => Error: fclose failed"); return 4; } /* cleanup curl stuff */ curl_easy_cleanup(curl_handle); return (failed) ? 10 : 0; } int PageManager::login(Account account) { if(debugMode) std::cout << " > Melde mit neuem Account an: Email: " << account.Email << " Passowort: " << account.Password << std::endl; auto reply = getServerRequest("https://serienstream.sx/login", false, std::string("email=" + account.Email + "&password=" + account.Password), true ); std::string html = reply.html; if(html == "" ) return 0; else if (html.find("Das Feld Email muss eine gültige E-Mail-Adresse enthalten.") != std::string::npos) std::cout << " => Error: Login failed: Das Feld Email muss eine gültige E-Mail-Adresse enthalten." << std::endl << " Email: '" << account.Email << "' Passwort: '" << account.Password << "'" << std::endl; else if (html.find("Das Passwort ist nicht korrekt") != std::string::npos) std::cout << " => Error: Login failed: Das Passwort ist nicht korrekt." << std::endl << " Email: '" << account.Email << "' Passwort: '" << account.Password << "'" << std::endl; else if (html.find("Ein Account mit dieser E-Mail Adresse wurde nicht gefunden.") != std::string::npos) std::cout << " => Error: Login failed: Ein Account mit dieser E-Mail Adresse wurde nicht gefunden." << std::endl << " Email: '" << account.Email << "' Passwort: '" << account.Password << "'" << std::endl; else if(html == "-1") return -1; else std::cout << " => Error: Login failed: Keine Weiterleitung bei Login." << std::endl << " Email: '" << account.Email << "' Passwort: '" << account.Password << "'" << std::endl; return -1; } std::string PageManager::getUrlAfterRedirect(std::string Url) { return getServerRequest(Url, true, "", false, true).url; } std::string PageManager::checkName(std::string Name) { std::string name = replace(Name, " ", "-"); std::string html = getServerRequest("https://serienstream.sx/serie/stream/" + name).html; if(html.find("Die gewünschte Serie wurde nicht gefunden oder ist im Moment deaktiviert.") != std::string::npos) { std::cout << "\33[2K\r => Die gewünschte Serie wurde nicht gefunden oder ist im Moment deaktiviert: '" << Name << "'" << std::endl; return "-1"; } else if (html.find("404 - Seite nicht gefunden") != std::string::npos) { std::cout << "\33[2K\r => Ungültiger Name: '" << Name << "'" << std::endl; return "-1"; } else if (html == "-1" || html == "") { return "-2"; } else { std::cout << "\33[2K\r > Name: " << name << std::endl; return name; } } std::string PageManager::getLinks(std::string HTML) { //Entderne alles vor den Links size_t pos = HTML.find("<ul class=\"row\">"); if(pos == std::string::npos) { std::cout << " => Error: Konnte Position von \"" << "<ul class=\"row\">" << " nicht finden" <<std::endl; return ""; } HTML.erase(0,pos); //Entferne alles nach den Links //pos = HTML.find("<script async="); pos = HTML.find("<script data-cfasync=\""); if(pos == std::string::npos) { std::cout << " => Error: Konnte Position von \"" << "<script async=" << "\" nicht finden" <<std::endl; return ""; } HTML.erase(pos,HTML.length() - pos); //Erstezte alle NewLine Zeichen durch nichts => 1Ne Zeile HTML = replace(HTML, "\n", ""); //HTML.replace("\n","").replace("</span>", "\n"); //Erstezte alle </span> Zeichen durch \n => 1 Hoster pro Zeil HTML = replace(HTML, "</span>", "\n"); //Greppe alle Zeilen mit Hoster HTML = grep(HTML,"href=\"/redirect/"); std::istringstream iStrStream( HTML + "\n" ); std::string line, ReturnValue; size_t pos2; while (getline(iStrStream, line).good()) { if(line == "") break; pos=line.find("data-lang-key="); if(pos == std::string::npos) { std::cout << " => Error: Konnte Position von \"data-lang-key=\" nicht finden." << std::endl; continue; } //entferne alles bis pos line.erase(0,pos); pos=line.find("data-link-id="); if(pos == std::string::npos) { std::cout << " => Error: Konnte Position von \"data-link-id=\" nicht finden." << std::endl; continue; } pos2=line.find("href=\""); if(pos2 == std::string::npos) { std::cout << " => Error: Konnte Position von 'href=\"' nicht finden." << std::endl; continue; } //Entferne alles von pos bis pos2 line.erase(pos,pos2-pos); pos=line.find("target="); if(pos == std::string::npos) { std::cout << " => Error: Konnte Position von \"target=\" nicht finden." << std::endl; continue; } pos2=line.find("title="); if(pos2 == std::string::npos) { std::cout << " => Error: Konnte Position von \"title=\" nicht finden." << std::endl; continue; } //entferne alles von pos bis pos2 line.erase(pos,pos2-pos); pos=line.find("><"); if(pos == std::string::npos) { std::cout << " => Error: Konnte Position von \"><\" nicht finden." << std::endl; continue; } //entferne alles von pos bis zum ende line.erase(pos,line.length()-pos); line = replace(line, "title=\"Hoster ", "hoster=\""); ReturnValue+=line+"\n"; } if(ReturnValue.length() > 0) return ReturnValue.erase( ReturnValue.size()-1 , 1); else return ""; } int PageManager::counterContains(std::string text, std::string substring_with_prozent_i_for_number, int starte_mit_dieser_Zahl) { int i = starte_mit_dieser_Zahl; for (; text.find( replace(substring_with_prozent_i_for_number, "%i", std::to_string(i)) ) != std::string::npos; ++i); return i-1; } std::string PageManager::grep(std::string text, std::string substring, bool IgnoreCaseSensetifity) { std::istringstream iStrStream(text + "\n"); std::string line, returnValue; while( std::getline(iStrStream, line).good() ) //auto start_of_line_position = begin( line ); //auto end_of_line_position = end( line ); if(line.find(substring) != std::string::npos || ( IgnoreCaseSensetifity && upper_string(line).find(upper_string(substring)) != std::string::npos) ) returnValue += line + "\n"; if(returnValue.length() >= 1) return returnValue.erase(returnValue.length()-1,1); else return ""; } std::string PageManager::upper_string(const std::string &str) { std::string upper; transform(str.begin(), str.end(), std::back_inserter(upper), toupper); return upper; } size_t PageManager::getDate() { std::time_t now = std::time(nullptr); struct tm *tm_now = localtime(&now); return static_cast<size_t>( static_cast<double>(1900 + tm_now->tm_year) * 365.24220 + static_cast<double>(tm_now->tm_mon +1) * 30.43685 + tm_now->tm_mday); } std::string PageManager::getExePath() { #ifdef __linux__ char buff[PATH_MAX]; ssize_t len = ::readlink("/proc/self/exe", buff, sizeof(buff)-1); if (len == -1) { perror("Readlink proc self exe failed"); return ""; } else { buff[len] = '\0'; return std::string(buff); } #endif #ifdef _WIN32 wchar_t buffer[MAX_PATH + 1]; GetModuleFileName( nullptr, buffer, MAX_PATH ); std::wstring wstr(buffer); return std::string(wstr.begin(), wstr.end()); #endif } int PageManager::compareVersions(std::string Version1, std::string Version2) { std::string StringList[2] = { ( Version1 + "." ), ( Version2 + "." ) }; int Versions[2][3]; size_t pos; //Für beide Versionen: for (int n = 0; n < 2; ++n) { //Für 3 Punkte: for (int i = 0; i < 3; ++i) { //Wenn kein Punkt gefunden werden konnte => Error: if( (pos = StringList[n].find(".")) == std::string::npos) { std::cout << " => Error: Ungültige ProgrammVersion: '" << ( (n == 0) ? Version1 : Version2 ) << "'" << std::endl; return -1; //wenn punkt gefunden werden konnte } else { //Wenn der Teilstring keine Zahl ist error: if( !isNumber(StringList[n].substr(0, pos)) ) { std::cout << " => Error: Ungültige ProgrammVersion: (Keine Zahl): '" << ( (n == 0) ? Version1 : Version2 ) << "'" << std::endl; return -1; } else { //Sonst speicher Zahl in array und entferne den anfang des strings Versions[n][i] = atoi(StringList[n].substr(0, pos).c_str()); StringList[n].erase(0, pos + 1); } } } } for (int i = 0; i < 3; ++i) { if(Versions[0][i] > Versions[1][i]) { return 2; } else if(Versions[0][i] < Versions[1][i]) { return 1; } } return 0; } int PageManager::writeToFile(std::vector<std::string> paths, std::string text) { if(paths.size() == 0) return 0; std::ofstream of; for(auto path : paths) { of.open(path, std::ios::out | std::ios::app); if(!of.is_open()) { perror((" => Error: Konnte Output: '" + path + "' Datei nicht öffnen").c_str()); return -1; } of << text << std::endl; of.close(); } return 0; } std::string PageManager::chooseHosterLink(std::string HosterList, std::string Hoster_with_Highst_Priority_at_First, std::string languages_with_highst_priority_at_first, bool withWarnMsg) { std::istringstream SListLang ( replace( languages_with_highst_priority_at_first, ",", "\n") + "\n" ); int LangId = 0; size_t pos = 0; std::string LanguageSortedHoster, Line, langId, hoster; //QTextStream stream(); //Für jede Sprache: while (getline(SListLang, langId).good()) { //Erst in schleife: weil es sonst ein problem wegen dem readdevice beim 2.ten durchlauf gibt std::istringstream SListHoster( replace( Hoster_with_Highst_Priority_at_First, ",", "\n") + "\n" ); if(langId == "") continue; else if ( upper_string( langId ) == "GERDUB" ) LangId=1; else if ( upper_string( langId ) == "ENG" ) LangId=2; else if ( upper_string( langId ) == "GERSUB" ) LangId=3; else { std::cout << " => Error: Unbekannte Sprache: " << langId << std::endl; continue; } //Liste aller Links mit der Sprache des durchgangs der schleife LanguageSortedHoster = grep(HosterList, ( "data-lang-key=\"" + std::to_string(LangId) + "\"" ) ); //std::cout << "Alle Folgen mi der Sprache " << langId << ":\n'" << LanguageSortedHoster << "'" << std::endl; //Wenn keine Links zu der Sprache gefunden worden sind if(LanguageSortedHoster == "") { if(withWarnMsg) std::cout << "Warnung: Es wurden keine Links für die Sprache '" <<langId << "' gefunden." << std::endl; continue; } //Upper all Hoster Name in List: for (size_t posHoster = LanguageSortedHoster.find("hoster=\""); posHoster != std::string::npos; posHoster = LanguageSortedHoster.find("hoster=\"", posHoster + 8)) { size_t posNextAnfz = LanguageSortedHoster.find("\"", posHoster + 8); if(posNextAnfz == std::string::npos) { std::cout << " => Error: Konnte \" in chooseHosterLink() nicht finden." << std::endl; break; } else LanguageSortedHoster.replace(posHoster + 8, posNextAnfz - posHoster - 8, upper_string(LanguageSortedHoster.substr(posHoster + 8, posNextAnfz - posHoster - 8)) ); } //Für jeden Angegebenen Hoster: while (getline(SListHoster, hoster).good()) { //Wenn es den hoster bei dieser prache nicht gibt, wähle nächsten if(LanguageSortedHoster.find( "hoster=\"" + upper_string(hoster) + "\"" ) == std::string::npos) { if(withWarnMsg) std::cout << "Warnung: Hoster " << hoster << " gibt es bei der sprache" << langId << " nicht " << std::endl; continue; } Line = grep(LanguageSortedHoster + "\n", ("hoster=\"" + upper_string(hoster) + "\"" ) ); pos = Line.find("href=\""); if(pos == std::string::npos) { std::cout << " => Error: Konnte 'href=\"' in chooseHosterLink() nicht finden." << std::endl; continue; } Line.erase(0, pos + 6/*static_cast<int>(strlen("href=\""))*/); pos = Line.find("\""); if(pos == std::string::npos) { std::cout << " => Error: Konnte '\"' in chooseHosterLink() nicht finden." << std::endl; continue; } return Line.erase(pos, Line.length()-pos); } if(withWarnMsg) { std::cout << "Warnung: Die Hoster '" << Hoster_with_Highst_Priority_at_First << "' gab es für die Sprache '" << langId << "' nicht." << std::endl; std::cout << "INFO: Andere Hoster zu dieser Sprache: \n" << LanguageSortedHoster << std::endl; } } return ""; } std::string PageManager::getLinkAfterHosterBasedOperation(std::string url) { size_t pos1 = 0, pos2 = 0; if(debugMode) std::cout << "Convert url: " << url << " ->"<< std::endl; if((pos1 = url.find("://")) == std::string::npos) { std::cout << " => Error: Konnte '://' in getLinkAfterHosterBasedOperation() nicht finden." << std::endl; return ""; } else if((pos2 = url.find(".", pos1 + 3)) == std::string::npos) { std::cout << " => Error: Konnte '.' nach '://' in getLinkAfterHosterBasedOperation() nicht finden." << std::endl; return ""; } std::string hoster = url.substr(pos1 + 3, pos2 - pos1 - 3); if(hoster == "vivo") { url = replace(url, "/embed/", "/"); url = replace(url, "http://", "https://"); } else if (hoster == "...") { } if(debugMode) std::cout << " -> zu... " << url << std::endl; return url; }