diff --git a/g++/accountManager.cpp b/g++/accountManager.cpp index d752946..f8555b1 100644 --- a/g++/accountManager.cpp +++ b/g++/accountManager.cpp @@ -9,7 +9,7 @@ AccountManager::AccountManager(std::string pathToFile, std::string pathToAccount exit(12); ifs.open(pathToFile); if(!ifs.is_open()) { - std::cout << "Konnte Account File nicht öffnen" << std::endl; + std::cout << " => Error: Konnte Account File nicht öffnen" << std::endl; exit(13); } } @@ -42,7 +42,7 @@ AccountManager::AccountManager(std::string pathToFile, std::string pathToAccount Account AccountManager::getNextAccount() { if(accounts.size() == 0) { - std::cout << "Keine Accounts vorhanden." << std::endl; + std::cout << " => Error: Keine Accounts vorhanden." << std::endl; exit(36); } size_t accountNumber = getLastAccountNumber(); @@ -60,13 +60,35 @@ int AccountManager::writeDefault(std::string path) { std::ofstream ofs(path); if(!ofs.is_open()) { - perror((std::string("Konnte Account Datei nicht öffnen: ") + path).c_str()); + perror((std::string(" => Error: Konnte Account Datei nicht öffnen: ") + path).c_str()); return -1; } - std::cout << "Erstelle Datei mit Accounts unter: " << path << "..." < Erstelle Datei mit Accounts unter: " << path << "..." < Error: Konnte Account Number Datei nicht erstellen"); exit(34); } } @@ -113,7 +187,7 @@ int AccountManager::setLastAccountNumber(size_t number) std::ofstream ofs; ofs.open(pathToAccountNumberFile, std::ios::trunc); if(!ofs.is_open()) { - std::cout << "Account Number Datei ist nicht geöffnet." << std::endl; + std::cout << " => Error: Account Number Datei ist nicht geöffnet." << std::endl; return 110; } //fStream.clear(); diff --git a/g++/pageManager.cpp b/g++/pageManager.cpp index 9042f81..1cc478a 100644 --- a/g++/pageManager.cpp +++ b/g++/pageManager.cpp @@ -3,12 +3,12 @@ PageManager::PageManager(std::string sock5Proxy, std::string cookieFilePath) : sock5Proxy(sock5Proxy), cookieFilePath(cookieFilePath) { - + curl_global_init(CURL_GLOBAL_ALL); } PageManager::~PageManager() { - remove(cookieFilePath.c_str()); + curl_global_cleanup(); } void PageManager::setProxy(std::string ip, int port) @@ -41,7 +41,7 @@ Reply PageManager::getServerRequest(std::string Url, bool useCookies, std::strin char *url; std::string returnUrl; - std::cout << "Lade: '" << Url << "'..." << std::flush; + std::cout << ( "\33[2K\rLade: '" + Url + "'..." ) << std::flush; curl = curl_easy_init(); if(!curl) { @@ -71,10 +71,10 @@ Reply PageManager::getServerRequest(std::string Url, bool useCookies, std::strin if(res != CURLE_OK) { if(timeout == maxTimeout) { - perror((std::string(" => Error: curl_easy_perform() failed: ") + curl_easy_strerror(res)).c_str()); + perror((std::string("\33[2K\r => Error: curl_easy_perform() failed: ") + curl_easy_strerror(res)).c_str()); return Reply("-1"); } else { - std::cout << "\33[2K\r" << " => Warning: Versuch " << timeout << " von " << maxTimeout << ": curl_easy_perform() failed: " << curl_easy_strerror(res) << std::flush; + 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 { @@ -86,7 +86,7 @@ Reply PageManager::getServerRequest(std::string Url, bool useCookies, std::strin //Get Url res = curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &url); if( res != CURLE_OK || !url ) { - perror((std::string(" => Error: curl_easy_getinfo failed: ") + curl_easy_strerror(res)).c_str()); + perror((std::string("\33[2K\r => Error: curl_easy_getinfo failed: ") + curl_easy_strerror(res)).c_str()); return Reply("-1"); } else returnUrl=url; @@ -131,19 +131,19 @@ std::string PageManager::getUrlAfterRedirect(std::string Url) std::string PageManager::checkName(std::string Name) { std::string name = replace(Name, " ", "-"); - std::cout << " > Name: " << name << std::endl; std::string html = getServerRequest("https://s.to/serie/stream/" + name).html; if(html.find("Die gewünschte Serie wurde nicht gefunden oder ist im Moment deaktiviert.") != std::string::npos) { - std::cout << " => Error: Die gewünschte Serie wurde nicht gefunden oder ist im Moment deaktiviert: " << Name << std::endl; + std::cout << "\33[2K\r => Error: 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 << " => Error: Ungültiger Name: " << Name << std::endl; + std::cout << "\33[2K\r => Error: Ungültiger Name: " << Name << std::endl; return "-1"; } else if (html == "-1") { return "-1"; } else { + std::cout << "\33[2K\r > Name: " << name << std::endl; return name; } } diff --git a/g++/pageManager.h b/g++/pageManager.h index 276ecab..5026ccb 100644 --- a/g++/pageManager.h +++ b/g++/pageManager.h @@ -1,16 +1,14 @@ #ifndef MANAGEPAGE_H #define MANAGEPAGE_H -#include -// if complied for windows; everything is in */projectfolder/curl/ -#include +#include "accountManager.h" + +#include "curl/curl.h" #include #include #include - #include -#include "accountManager.h" struct Reply { Reply() {} diff --git a/g++/parameterManager.cpp b/g++/parameterManager.cpp index 2367128..295aa25 100644 --- a/g++/parameterManager.cpp +++ b/g++/parameterManager.cpp @@ -4,12 +4,15 @@ void setPaths(Settings &settings) { //Path settings std::string executablePathTo = getexepath(); - std::cout << "Path " << executablePathTo << std::endl; executablePathTo.erase(executablePathTo.find_last_of(settings.pathSymbol) + 1 , executablePathTo.length() - ( executablePathTo.find_last_of(settings.pathSymbol) + 1) ); - if(!dirExists(executablePathTo + "src" + settings.pathSymbol)) - system(std::string("mkdir \"" + executablePathTo + "src" + settings.pathSymbol + "\"").c_str()); + if(!dirExists(executablePathTo + "src" + settings.pathSymbol)) { + if(system(std::string("mkdir \"" + executablePathTo + "src" + settings.pathSymbol + "\"").c_str()) == 0) + std::cout << " => Erfolgreich Ordner 'src' erstellt." << std::endl; + else + std::cout << " => Error: Ordner '" << executablePathTo << "src' konnte nicht erstellt werden." << std::endl; + } if(dirExists(executablePathTo + "src" + settings.pathSymbol)) executablePathTo+="src" + std::string(1, settings.pathSymbol); @@ -17,6 +20,7 @@ void setPaths(Settings &settings) settings.accountFilePath = executablePathTo + "Accounts"; settings.accountNumberPath = executablePathTo + "Account_Number"; settings.serienListPath = executablePathTo + "SerienListe"; + settings.defaultsFilePath = executablePathTo + "Defaults"; } @@ -25,6 +29,8 @@ int manageParameter(Settings &settings, int argc, char **argv) //Path settings setPathSymbol(settings); setPaths(settings); + if(loadDefaulOptions(settings) != 0) + return 28; if(argc < 2) { std::cout << " => Error: Keine Unteroption angegeben." << std::endl; @@ -33,7 +39,7 @@ int manageParameter(Settings &settings, int argc, char **argv) return 1; } - int res = compare("--help\ndefault\nurl\n--version\nsearch\ninfo", argv[1]); + int res = compare("--help\ndefault\nurl\n--version\nsearch\ninfo\nclean", argv[1]); if(res != 1) { std::cout << " => Error: " << ( (res == 0) ? std::string("Unbekannte Unteroption: '") + argv[1] + "'" : std::string("Mehrere Optionen für '") + argv[1] + std::string("' gefunden.") ) << std::endl; @@ -66,12 +72,183 @@ int manageParameter(Settings &settings, int argc, char **argv) argv[1][0] = '\0'; return unterOption_info(&settings, argc, argv); + } else if (strncmp(argv[1], "clean", strlen(argv[1])) == 0) { + argv[1][0] = '\0'; + unterOption_clean(&settings, argc, argv); + return -1; + } else { std::cout << "Error: Invalid option " << argv[1] << ", but not detected in compare-Function" << std::endl; return 3; } } +int loadDefaulOptions(Settings &settings) +{ + std::fstream ifs(settings.defaultsFilePath); + if(!ifs.is_open()) { + std::ofstream ofs(settings.defaultsFilePath); + if(!ofs.is_open()) { + std::cout << " => Error: Konnte Defaults-Datei nicht öffnen: " << errno << std::endl; + return 89; + } else { + std::cout << " => Erstelle Defaults-Datei: " << settings.defaultsFilePath << std::endl; + ofs << "#Mit # kann man eine Zeile deaktivieren." << std::endl; + ofs << "DefaultFileVersion="<< settings.defaultFileVersion << std::endl; + ofs << "#DebugModus=false" << std::endl; + ofs << std::endl; + ofs << "#Socks5Proxy=127.0.0.1:9050" << std::endl; + ofs << "#FarbloseAusgabe=false" << std::endl; + ofs << "#OutputFile=/tmp/a" << std::endl; + ofs << std::endl; + ofs << "#default-GenaueHoster=Vivo,GoUnlimited" << std::endl; + ofs << "#default-Sprachen=GerDub,GerSub,Eng" << std::endl; + ofs << "#default-CheckSuchMuster=S%Staffel%E%Folge%" << std::endl; + ofs << "#default-CheckMaxDirs=20" << std::endl; + ofs << "#default-maxThreads=0" << std::endl; + ofs << std::endl; + ofs << "#search-AchteAufGroßUndKleinschreibung=false" << std::endl; + + + ofs.close(); + } + ifs.open(settings.defaultsFilePath); + if(!ifs.is_open()) { + std::cout << " => Error: Konnte Defaults-Datei nach dem erstellen nicht öffnen: " << errno << std::endl; + return 97; + } + } + + std::string line; + while (std::getline(ifs, line).good()) { + if(line.find("#") != std::string::npos || line == "") + continue; + else if ( line.find("=") == std::string::npos ) { + std::cout << " => Warnung: Bitte Info-Texte mit '#' am Anfang: Ungültige Option '" << line << "'." << std::endl; + continue; + } + std::string what = line.substr(0, line.find("=")), data = line.substr(line.find("=") + 1, line.length() - line.find("=") -1); + if(what == "") { + + } else if (what == "Socks5Proxy") { ///--- + if(data.find(":") == std::string::npos) { + std::cout << " => Error_Defaults: Ungültiger Socks5 Proxy: '" << data << "'" << std::endl; + return 31; + } + std::string ip = data.substr(0, data.find(":")); + std::string portStr = data.substr(data.find(":") + 1, data.length() - data.find(":")); + int port = atoi(portStr.c_str()); + if(std::to_string(port) != portStr || port <= 0) { + std::cout << " => Error_Defaults: Socks5 Proxy: Invalid Port: " << portStr << std::endl; + return 32; + } else if (ip == "") { + std::cout << " => Error_Defaults: Socks5 Proxy: Invalid Ip Addresse: " << ip << std::endl; + return 34; + } else if(settings.debugMode) { + std::cout << " > Defaults: Proxy Addresse: "<< ip << ":" << port << std::endl; + } + settings.proxy_ip = ip; + settings.proxy_port = port; + + } else if (what == "DefaultFileVersion") { ///--- + if(data != settings.defaultFileVersion) + std::cout << " => Warnung: Veraltetes Defaults-File. Löschen sie die Datei, um die neuste Version zu bekommen." << std::endl; + + } else if (what == "DebugModus") { ///--- + if(data == "true") + settings.debugMode=true; + else if (data == "false") + settings.debugMode=false; + else { + std::cout << " => Error_Defaults: DebugModus: Ungültiger Wert für 'true/false': " << data << std::endl; + return 161; + } + if(settings.debugMode) + std::cout << " > Defaults: DebugMode: true" << std::endl; + + } else if (what == "default-GenaueHoster") { + settings.genaueHoster=data; + if(settings.debugMode) + std::cout << " > Defaults: GenaueHoster: " << settings.genaueHoster << std::endl; + + } else if (what == "default-Sprachen") { + settings.languages=data; + if(settings.debugMode) + std::cout << " > Defaults: Sprachen: " << settings.languages << std::endl; + + } else if (what == "default-CheckSuchMuster") { + settings.default_Searchmuster=data; + if(settings.debugMode) + std::cout << " > Defaults: SuchMuster: " << settings.default_Searchmuster << std::endl; + + } else if (what == "default-CheckMaxDirs") { + settings.default_maxDirs = atoi(data.c_str()); + if(std::to_string(settings.default_maxDirs) != data ) { + std::cout << " => Error_Defaults: default-CheckMaxDirs: Ungültige Zahl: " << data << std::endl; + return 18; + } + if(settings.debugMode) + std::cout << " > Defaults: default-CheckMaxDirs: " << settings.default_maxDirs << std::endl; + + + } else if (what == "default-maxThreads") { + settings.maxThreads = static_cast(atoi(data.c_str())); + if(std::to_string(settings.maxThreads) != data ) { + std::cout << " => Error_Defaults: Ungültige Zahl: " << data << std::endl; + return 18; + } + if(settings.debugMode) + std::cout << " > Defaults: MaxThreads: " << settings.maxThreads << std::endl; + + } else if (what == "FarbloseAusgabe") { + if(data == "true") + settings.colorless=true; + else if (data == "false") + settings.colorless=false; + else { + std::cout << " => Error_Defaults: FarbloseAusgabe: Ungültiger Wert für 'true/false': " << data << std::endl; + return 207; + } + if(settings.debugMode) + std::cout << " > Defaults: FarbloseAusgabe: " << settings.colorless << std::endl; + + } else if (what == "search-AchteAufGroßUndKleinschreibung") { + if(data == "true") + settings.search_IgnoreUpperLower=false; + else if (data == "false") + settings.search_IgnoreUpperLower=true; + else { + std::cout << " => Error_Defaults: search-AchteAufGroßUndKleinschreibung: Ungültiger Wert für 'true/false': " << data << std::endl; + return 227; + } + if(settings.debugMode) + std::cout << " > Defaults: search-AchteAufGroßUndKleinschreibung: " << settings.search_IgnoreUpperLower << std::endl; + + } else if (what == "OutputFile") { + settings.outputFilePath = data; + if(settings.debugMode) + std::cout << " > Defaults: OutputFile: " << settings.outputFilePath << std::endl; + + } else if (what == "") { + + } else if (what == "") { + + } else if (what == "") { + + } else if (what == "") { + + } else { + std::cout << " => Warnung: Unbekannte Default-Option: '" << what << "'." << std::endl; + } + } + + + + + ifs.close(); + return 0; +} + int unterOption_help() { std::cout << "Aufruf: " << getProgramName() << " [Unteroption] [PARAMETER]" << std::endl << std::endl; @@ -80,7 +257,9 @@ int unterOption_help() << "\t„--version“\tVersion des Programmes" << std::endl << "\t„url“\t\tModus um eigene Redirect-Links umzuwandeln." << std::endl << "\t„default“\tModus um Links von Serien zu bekommen." << std::endl - << "\t„search“\tModus um Serien zu suchen." << std::endl; + << "\t„search“\tModus um Serien zu suchen." << std::endl + << "\t„info“\t\tModus um Infos einer Serien zu bekommen." << std::endl + << "\t„clean“\t\tModus um Cookie-Files zu löschen." << std::endl; return -1; } @@ -104,8 +283,9 @@ int unterOption_default(Settings *settings, int argc, char ** argv) {"check-dir", required_argument, nullptr, 'C'}, {"check-muster", required_argument, nullptr, 'm'}, - {"check-max-dirs", required_argument, nullptr, 't'}, + {"check-max-dirs", required_argument, nullptr, 'D'}, + {"threads", required_argument, nullptr, 't'}, {"help", no_argument, nullptr, 'h'}, {"colorless", no_argument, nullptr, 'c'}, @@ -115,7 +295,7 @@ int unterOption_default(Settings *settings, int argc, char ** argv) }; - while( ( c = getopt_long (argc, argv, "p:g:l:o:e:E:s:S:C:m:t:hcd", long_opts, nullptr) ) != -1 ) { + while( ( c = getopt_long (argc, argv, "p:g:l:o:e:E:s:S:C:m:D:t:hcd", long_opts, nullptr) ) != -1 ) { switch(c) { case 'p': { if(!optarg || std::string(optarg) == "") @@ -217,20 +397,33 @@ int unterOption_default(Settings *settings, int argc, char ** argv) if(optarg) settings->default_Searchmuster = optarg; if(settings->debugMode) - std::cout << "SearchMuster: " << settings->default_Searchmuster << std::endl; + std::cout << " SearchMuster: " << settings->default_Searchmuster << std::endl; break; - case 't': + case 'D': if(!optarg) break; settings->default_maxDirs = atoi(optarg); if(std::to_string(settings->default_maxDirs) != std::string(optarg) ) { - std::cout << "[-t]: Invalid Count: " << optarg << std::endl; + std::cout << "[-D]: Invalid Count: " << optarg << std::endl; return 18; } if(settings->debugMode) - std::cout << "SearchMuster: " << settings->default_Searchmuster << std::endl; + std::cout << "CheckMaxDirs: " << settings->default_maxDirs << std::endl; break; + case 't': + if(!optarg) + break; + settings->maxThreads = static_cast(atoi(optarg)); + if(std::to_string(settings->maxThreads) != std::string(optarg) ) { + std::cout << "[-t]: Ungültige Zahl: " << optarg << std::endl; + return 18; + } + if(settings->debugMode) + std::cout << "MaxThreads: " << settings->maxThreads << std::endl; + + break; + case 'C': if(!optarg) break; @@ -312,7 +505,7 @@ void unterOption_default_help() << "\t -> Muster mit dem Überprüft wird, ob diese Folge in einem Ordner ist. Default: S%Staffel%E%Folge%" << std::endl << "\t -> %Staffel% ist eine Variable für die Staffel mit 0 + Staffel, wenn Staffel < 10. " << std::endl << "\t -> %Folge% ist eine Variable für die Folge mit 0 + Folge, wenn Folge < 10. " << std::endl - << "\t-t, --check-max-dirs" << std::endl + << "\t-D, --check-max-dirs" << std::endl << "\t -> Maximale Anzahl der Ordner, die auf Dateien untersucht werden. Default: 20" << std::endl << std::endl << " > Durchlaufoptionen:" << std::endl @@ -330,6 +523,12 @@ void unterOption_default_help() << "\t-S [Staffel], --stop-season [Staffel]" << std::endl << "\t -> Das Programm stopt mit dieser Staffel. Beachte Verwendung mit -E." << std::endl << "\t Zum deaktivieren Staffel <= 0 verwenden. Default: 0" << std::endl + << " > Multi-Thrading Optionen:" << std::endl + << "\t-t [maxThreads], --threads [maxThreads]" << std::endl + << "\t -> Das Programm startet für jede Folge einen eigenen Thread," << std::endl + << "\t -> bis die maximale Anzahl ereicht wurde. Dann wartet es auf" << std::endl + << "\t -> das enden aller Threads und fängt dann wieder von vorne an." << std::endl + << "\t -> Zum deaktivieren von Multithreading '0' verwenden. Default: 0" << std::endl << std::endl << " > Help-Optionen" << std::endl << "\t-h, --help" << std::endl; @@ -546,38 +745,13 @@ void unterOption_search_help() << "\t-e, --exactly-writing" << std::endl << "\t -> Achte auf Groß und kleinschreibung bei der Suche. Default: false" << std::endl << "\t-u, --update" << std::endl - << "\t -> Update die Serienliste. Default: false" << std::endl + << "\t -> Update die Serienliste." << std::endl << "\t-h, --help" << std::endl << "\t -> Gibt dieses Helpmenü aus." << std::endl; } -int compare(std::string All_Options_with_komma_between, std::string input) -{ - std::istringstream iStrStream( All_Options_with_komma_between + "\n"); - std::string line; - int allFounds = 0; - while (getline(iStrStream, line).good()) - if(strncmp(line.c_str(), input.c_str(), input.length()) == 0) { - allFounds++; - //std::cout << "Unteroption '" << input << "' stimmt mit '" << line << "' überein." << std::endl; - } - return allFounds; -} - -bool dirExists(std::string dir) -{ - struct stat sb; - return (stat(dir.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode)) ? true : false; -} - -std::string getProgramName() -{ - return getexepath().erase(0, ( getexepath().find_last_of("/\\") != std::string::npos ) ? getexepath().find_last_of("/\\") +1 : 0 ); -} - - int unterOption_info(Settings *settings, int argc, char **argv) { settings->modus = Modus::INFO_MODUS; @@ -672,6 +846,66 @@ void unterOption_info_help() } +void unterOption_clean(Settings * settings, int argc, char **argv) +{ + if(argc > 2) + if(strncmp("--help", argv[2], strlen(argv[2])) == 0) { + std::cout << "Aufruf: " << getProgramName() << " clean" << std::endl << std::endl; + std::cout << "Mit dieser Function werden die Cookie-Files gelöscht." << std::endl; + return; + } + + unsigned count = 0; + if(fileExists(settings->cookieFilePath)) { + if(remove(settings->cookieFilePath.c_str()) != 0) { + std::cout << " => Error: Das löschen von " << settings->cookieFilePath << " ist fehlgeschlagen: " << errno << std::endl; + return; + } else + count++; + } + + for (unsigned i = 0; i < UINT_MAX && fileExists(settings->cookieFilePath + std::to_string(i)); i++) { + if(remove( (settings->cookieFilePath + std::to_string(i)).c_str() ) != 0) { + std::cout << " => Error: Das löschen von " << settings->cookieFilePath + std::to_string(i) << " ist fehlgeschlagen: " << errno << std::endl; + return; + } else { + count++; + } + } + + if(count == 0) + std::cout << " => Nichts zu tun: Keine Cookies vorhanden." << std::endl; + else + std::cout << " => " << count << " Cookie-File(s) gelöscht." << std::endl; + + return; +} + + +int compare(std::string All_Options_with_komma_between, std::string input) +{ + std::istringstream iStrStream( All_Options_with_komma_between + "\n"); + std::string line; + int allFounds = 0; + while (getline(iStrStream, line).good()) + if(strncmp(line.c_str(), input.c_str(), input.length()) == 0) { + allFounds++; + //std::cout << "Unteroption '" << input << "' stimmt mit '" << line << "' überein." << std::endl; + } + return allFounds; +} + +bool dirExists(std::string dir) +{ + struct stat sb; + return (stat(dir.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode)) ? true : false; +} + +std::string getProgramName() +{ + return getexepath().erase(0, ( getexepath().find_last_of("/\\") != std::string::npos ) ? getexepath().find_last_of("/\\") +1 : 0 ); +} + std::string getexepath() { #ifdef linux @@ -680,7 +914,7 @@ std::string getexepath() return std::string( result, (count > 0) ? static_cast(count) : 0 ); #endif #ifdef ABC ///_WIN32 - wchar_t result[ MAX_PATH ]; + //wchar_t result[ MAX_PATH ]; char buffer[MAX_PATH]; return std::string( result, GetModuleFileName( NULL, buffer, MAX_PATH ) ); //GetModuleFileName(NULL, result, MAX_PATH) ; @@ -697,3 +931,9 @@ void setPathSymbol(Settings &settings) settings.pathSymbol = '\\'; #endif } + +bool fileExists (const std::string& name) { + struct stat buffer; + return (stat (name.c_str(), &buffer) == 0 && S_ISREG(buffer.st_mode)); +} + diff --git a/g++/parameterManager.h b/g++/parameterManager.h index 2d2f23c..f0e8c29 100644 --- a/g++/parameterManager.h +++ b/g++/parameterManager.h @@ -6,7 +6,7 @@ #include #include #include - +#include #include // PATH_MAX #include // readlink() @@ -30,13 +30,15 @@ struct Settings { std::string name, accountFilePath = "/tmp/a", - accountNumberPath= "/tmp/b", + accountNumberPath= "/tmp/a_n", cookieFilePath = "/tmp/S_New4_cookies", serienListPath = "/tmp/SerienListe", + defaultsFilePath = "/tmp/defaults", proxy_ip = "127.0.0.1", languages = "GerDub,GerSub,Eng", genaueHoster = "Vivo,GoUnlimited", - version = "2.1.2", + version = "2.3.0", + defaultFileVersion="1.3", outputFilePath = "", default_checkDirPath = "", default_Searchmuster = "S%Staffel%E%Folge%"; @@ -53,18 +55,22 @@ struct Settings { proxy_port = 9050, default_maxDirs = 20; char pathSymbol = '/'; + unsigned maxThreads = 0; }; int manageParameter(Settings &settings, int argc, char ** argv); -std::string getProgramName(); +int loadDefaulOptions(Settings & settings); int compare(std::string All_Options_with_komma_between, std::string input); -void setPaths(Settings &settings); -bool dirExists(std::string dir); +std::string getProgramName(); std::string getexepath(); -void setPathSymbol(Settings &settings); +void setPathSymbol(Settings &settings); +void setPaths(Settings &settings); + +bool fileExists (const std::string& name); +bool dirExists(std::string dir); int unterOption_help(); @@ -80,5 +86,7 @@ void unterOption_search_help(); int unterOption_info(Settings * settings, int argc, char **argv); void unterOption_info_help(); +void unterOption_clean(Settings * settings, int argc, char **argv); + #endif // PARAMETERMANAGER_H diff --git a/g++/programManager.cpp b/g++/programManager.cpp index ef60211..9133b4e 100644 --- a/g++/programManager.cpp +++ b/g++/programManager.cpp @@ -1,20 +1,31 @@ #include "programManager.h" + ProgramManager::ProgramManager() + : nextThread(0) { } ProgramManager::~ProgramManager() { - + for(auto e : threadList) { + delete e->pageManager; + delete e; + e = nullptr; + } } int ProgramManager::start(Settings *settings) { pageManager.setProxy(settings->proxy_ip, settings->proxy_port); - pageManager.setCookieFilePath(settings->cookieFilePath); pageManager.setDebugMode(settings->debugMode); + pageManager.setCookieFilePath(settings->cookieFilePath); + if(dirExists(settings->cookieFilePath)) { + std::cout << " => Error: Kann Cokkie-File nicht erstellen: Es existiert bereits ein Ordner mit diesem Namen: \n '" + << settings->cookieFilePath << "'." << std::endl; + return 174; + } switch (settings->modus) { case Modus::DEFAULT_MODUS: @@ -30,6 +41,77 @@ int ProgramManager::start(Settings *settings) } } +void * threadFunction(void * data) { + ThreadData * myThreadData = reinterpret_cast(data); + myThreadData->returnValue=""; + myThreadData->exitState=0; + + + Reply tmp_reply = myThreadData->pageManager->getServerRequest(myThreadData->pageManager->UrlPraefix + myThreadData->nameInUrl + + "/staffel-" + std::to_string(myThreadData->staffel) + "/episode-" + std::to_string(myThreadData->folge)); + if(tmp_reply.html == "-1") + return myThreadData->setState(10); + std::string allLinks = myThreadData->pageManager->getLinks(tmp_reply.html); + std::string Link = myThreadData->pageManager->chooseHosterLink(allLinks, myThreadData->settings->genaueHoster, myThreadData->settings->languages); + + if(myThreadData->settings->debugMode) + std::cout << " > Thread " << myThreadData->id << allLinks << std::endl << ( (Link == "") ? "" : " -> Link: 'https://s.to") << Link << ( (Link == "") ? "" : "'\n" ); + + + + + std::string folgenID = std::string((myThreadData->staffel == -1 || myThreadData->folge == -1 ) ? "" : "S" + std::string( (myThreadData->staffel < 10) ? "0" : "" ) + std::to_string(myThreadData->staffel) + + "E" + std::string( (myThreadData->folge < 10) ? "0" : "" ) + std::to_string( myThreadData->folge ) ); + std::string green = ((myThreadData->settings->colorless) ? "" : "\033[32m"), + red = ((myThreadData->settings->colorless) ? "" : "\033[31m"), + orange =((myThreadData->settings->colorless) ? "" : "\033[33m"), + blue = ((myThreadData->settings->colorless) ? "" : "\033[34m"); + + if(Link == "") { + if(allLinks == "") { + myThreadData->returnValue = " => " + red + "KEINEN Hoster für die Folge " + folgenID + " gefunden." + "\033[0m"; + if(myThreadData->pageManager->writeToFile(myThreadData->settings->outputFilePath, std::string("KEINEN Hoster für die Folge ") + folgenID + std::string(" gefunden.")) != 0) + return myThreadData->setState(14); + } + else { + myThreadData->returnValue = " => " + orange + "Keinen PASSENDEN Hoster für die Folge " + folgenID + " gefunden." + "\033[0m" + "\n" + + "Alle Links:" + "\n" + + myThreadData->pageManager->replace( myThreadData->pageManager->replace( myThreadData->pageManager->replace( allLinks, "data-lang-key=\"1\"", "language=\"GerDub\"" ), + "data-lang-key=\"2\"", "language=\"Eng\"" ), "data-lang-key=\"3\"", "language=\"GerSub\""); + if(myThreadData->pageManager->writeToFile(myThreadData->settings->outputFilePath, std::string("Keinen PASSENDEN Hoster für die Folge ") + folgenID + std::string(" gefunden.")) != 0) + return myThreadData->setState(15); + } + return myThreadData->setState(0); + } + + for (int i = 1; i <= 3; ++i) { + std::string newUrl = myThreadData->pageManager->getUrlAfterRedirect("https://s.to" + Link); + if (newUrl == "-1") { + return myThreadData->setState(16); + } else if(newUrl.find("/s.to/redirect/") != std::string::npos ) { + if(myThreadData->settings->debugMode) + std::cout << " > Thread " << myThreadData->id << "Warnung: Redirect Link nach umwandlung (Capcha?) --> Neuer Account" << std::endl; + if(myThreadData->pageManager->login(myThreadData->accountManager->getNextAccount()) != 0) + return myThreadData->setState(17); + continue; + + } else { + myThreadData->returnValue = " => " + folgenID + ( (folgenID == "") ? "" : ": " ) + green + newUrl + "\033[0m"; + if(myThreadData->settings->outputFilePath != "") + if(myThreadData->pageManager->writeToFile(myThreadData->settings->outputFilePath,folgenID + ( (folgenID == "") ? "" : ": " ) + newUrl) != 0) + return myThreadData->setState(18); + return myThreadData->setState(0); + } + } + myThreadData->returnValue = " => " + folgenID + ( (folgenID == "") ? "" : ": " ) + red + "https://s.to" + Link + "\033[0m"; + if(myThreadData->settings->outputFilePath != "") + if(myThreadData->pageManager->writeToFile(myThreadData->settings->outputFilePath, folgenID + ( (folgenID == "") ? "" : ": " ) + Link) != 0) + return myThreadData->setState(19); + return myThreadData->setState(0); + +} + + int ProgramManager::defaultModus(Settings *settings) { AccountManager accountManager(settings->accountFilePath, settings->accountNumberPath); @@ -54,7 +136,7 @@ int ProgramManager::defaultModus(Settings *settings) } //Überprüfe ob ein Muster existiert: - if(settings->default_Searchmuster == "") { + if(settings->default_checkDirPath != "" && settings->default_Searchmuster == "") { std::cout << " => Error: [-m]: Kein Muster angegeben." << std::endl; return 31; } @@ -81,9 +163,33 @@ int ProgramManager::defaultModus(Settings *settings) searchModus(settings); return 25; } - //Sonst melde sich bei s.to an und speicher cookies. - else if (pageManager.login(accountManager.getNextAccount()) != 0) - return 29; + + /* Wenn multihtreading seaktiviert ist, normal login sonst bereite threads vor + if(settings->maxThreads == 0) { + // melde bei s.to an und speicher cookies. + if (pageManager.login(accountManager.getNextAccount()) != 0) //---------------------------------------- + return 29; + }*/ + + if(settings->maxThreads > 0) { + for (unsigned i = 0; i < settings->maxThreads; ++i) { + if(dirExists(settings->cookieFilePath + std::to_string( i ))) { + std::cout << " => Error: Kann Cokkie-File nicht erstellen: Es existiert bereits ein Ordner mit diesem Namen: \n '" + << settings->cookieFilePath + std::to_string( i ) << "'." << std::endl; + return 174; + } + PageManager * pm = new PageManager("socks5://" + settings->proxy_ip + ":" + std::to_string(settings->proxy_port), settings->cookieFilePath + std::to_string( i )); + pm->setDebugMode(settings->debugMode); + + //pm->setProxy(settings->proxy_ip, settings->proxy_port); + //pm->setCookieFilePath(settings->cookieFilePath + std::to_string( i )); + + ThreadData * newThreadData = new ThreadData(i, 0, nameInUrl, -1, settings, &accountManager, pm); + threadList.push_back(newThreadData); + } + } + + //Write Name to File if -o is set pageManager.writeToFile(settings->outputFilePath, "Name: " + settings->name); //Finde die anzahl der staffel heraus: @@ -122,21 +228,51 @@ int ProgramManager::defaultModus(Settings *settings) } } - tmp_reply =pageManager.getServerRequest(pageManager.UrlPraefix + nameInUrl + "/staffel-" + std::to_string(staffel) + "/episode-" + std::to_string(folge)); - if(tmp_reply.html == "-1") - return 47; - std::string allLinks = pageManager.getLinks(tmp_reply.html); - std::string Link = pageManager.chooseHosterLink(allLinks, settings->genaueHoster, settings->languages); + //Multihreading Mode + if(settings->maxThreads > 0) { + //Wenn nex Thread noch in den Vector passt(weniger Threads als Max), dann Starte neuen mit data aus dem Vector... + if(nextThread < threadList.size()) { + threadList[nextThread]->exitState = 0; + threadList[nextThread]->setData(staffel, folge); + if(pthread_create(&threadList[nextThread]->thread, nullptr, threadFunction, reinterpret_cast(threadList[nextThread])) != 0 ) { + perror("pthread_creat failed"); + return 48; + } + nextThread++; + } else { // Sonnst warte bis alle Fertig sind und restarte die Folge + if(waitForThreads() != 0) + return 231; + nextThread=0; + folge--; + continue; + } - if(settings->debugMode) - std::cout << allLinks << std::endl << ( (Link == "") ? "" : " -> Link: 'https://s.to") << Link << ( (Link == "") ? "" : "'\n" ); - if(convertLink(Link, &accountManager, settings, staffel, folge, allLinks) != 0) - return 51; + } else { // Default Mode + tmp_reply =pageManager.getServerRequest(pageManager.UrlPraefix + nameInUrl + "/staffel-" + std::to_string(staffel) + "/episode-" + std::to_string(folge)); + if(tmp_reply.html == "-1") + return 50; + std::string allLinks = pageManager.getLinks(tmp_reply.html); + std::string Link = pageManager.chooseHosterLink(allLinks, settings->genaueHoster, settings->languages); - if(folge == settings->stopEpisode && settings->stopSeason < 1) // stoppe wenn stopfolge gleich der folge ist und stopstaffel nicht gesetzt wurde. + if(settings->debugMode) + std::cout << allLinks << std::endl << ( (Link == "") ? "" : " -> Link: 'https://s.to") << Link << ( (Link == "") ? "" : "'\n" ); + if(convertLink(Link, &accountManager, settings, staffel, folge, allLinks) != 0) + return 51; + + } + + if(folge == settings->stopEpisode && settings->stopSeason < 1) { // stoppe wenn stopfolge gleich der folge ist und stopstaffel nicht gesetzt wurde. + if(settings->maxThreads != 0) + if(waitForThreads() != 0) + return 261; return 0; - else if ( folge == settings->stopEpisode && staffel == settings->stopSeason) // stoppe wenn stopfolge = folge && stopstaffel == staffel + + } else if ( folge == settings->stopEpisode && staffel == settings->stopSeason) { // stoppe wenn stopfolge = folge && stopstaffel == staffel + if(settings->maxThreads != 0) + if(waitForThreads() != 0) + return 267; return 0; + } } //Setzte Startepisode zurück für nächste Staffel settings->startEpisode = 1; @@ -148,10 +284,34 @@ int ProgramManager::defaultModus(Settings *settings) } } + if(settings->maxThreads != 0) + if(waitForThreads() != 0) + return 292; + std::cout << " > Fertig" << std::endl; return 0; } +int ProgramManager::waitForThreads() +{ + for( auto &e : threadList) { + if( e->exitState != -1 && pthread_join(e->thread, nullptr) == 0) { + if(e->exitState != 0) { + std::cout << "\33[2K\r => Error: Thread gab error zurück." << std::endl; + return e->exitState; + } else + if(e->returnValue != "") + std::cout << ("\33[2K\r(T" + std::to_string(e->id) + ")" + e->returnValue ) << std::endl; + } + e->exitState = -1; + e->returnValue = ""; + e->setData(0, 0); + e->thread = 0; + } + return 0; +} + + int ProgramManager::directLinkModus(Settings *settings) { AccountManager accountManager(settings->accountFilePath, settings->accountNumberPath); @@ -166,8 +326,8 @@ int ProgramManager::directLinkModus(Settings *settings) std::istringstream iStrStream( pageManager.replace( settings->name, ",", "\n" ) + "\n" ); std::string line; - if(pageManager.login(accountManager.getNextAccount()) != 0) - return 71; + //if(pageManager.login(accountManager.getNextAccount()) != 0) + // return 71; while (getline(iStrStream, line).good()) { if(line.find("https://s.to/redirect/") == std::string::npos) { @@ -220,14 +380,24 @@ int ProgramManager::searchModus(Settings *settings) std::string finds = pageManager.grep(serienListe, settings->name, settings->search_IgnoreUpperLower); serienListe.clear(); // Speicher freigeben - //Text mit Farben versehen + /*//Text mit Farben versehen if(!settings->colorless) { for (size_t pos = pageManager.upper_string( finds ).find( pageManager.upper_string( settings->name ), 0); pos != std::string::npos; pos = pageManager.upper_string( finds ).find( pageManager.upper_string( settings->name ), pos + settings->name.length() + strlen("\033[37m\033[0m"))) finds.insert(pos, ( (finds.find(settings->name, pos) == pos) ? "\033[32m" : "\033[36m" ) ).insert(pos + settings->name.length() + strlen("\033[37m"), "\033[0m"); - } + }*/ + //Text mit Farben versehen + if(!settings->colorless) { + std::string UpperFinds = pageManager.upper_string( finds ); + std::string UpperName = pageManager.upper_string( settings->name ); + for (size_t pos = UpperFinds.find( UpperName, 0); pos != std::string::npos; pos = UpperFinds.find( UpperName, pos + settings->name.length() + strlen("\033[37m\033[0m"))) { + bool exaktGeschrieben = (finds.find(settings->name, pos) == pos); + finds.insert(pos, ( (exaktGeschrieben) ? "\033[32m" : "\033[36m" ) ).insert(pos + settings->name.length() + strlen("\033[37m"), "\033[0m"); + UpperFinds.insert(pos, ( (exaktGeschrieben ) ? "\033[32m" : "\033[36m" ) ).insert(pos + settings->name.length() + strlen("\033[37m"), "\033[0m"); + } + } //Ausgabe if(finds == "") { std::cout << " => Für '" << settings->name << "' wurde(n) keine Serie(n) gefunden." << std::endl; @@ -441,7 +611,7 @@ int ProgramManager::searchModus_update(Settings *settings) int ProgramManager::listDir(std::string &list,std::string path, int maxDepth) { - if(maxDepth == 0) + if(maxDepth <= 0) return 0; else if(!dirExists(path)) { std::cout << " => Error: Verzeichnis '" << path << "' existiert nicht oder ist kein Ordner." << std::endl; diff --git a/g++/programManager.h b/g++/programManager.h index 35ac267..7783d34 100644 --- a/g++/programManager.h +++ b/g++/programManager.h @@ -4,10 +4,34 @@ #include "pageManager.h" #include "parameterManager.h" #include "accountManager.h" -#include - #include + #include +#include + + +struct ThreadData +{ + ThreadData(unsigned id, pthread_t init, std::string nameinUrl,int exitStateInit, Settings * settings, AccountManager * accountMg, PageManager * pM) + : id(id), thread(init), nameInUrl(nameinUrl), exitState(exitStateInit), settings(settings), accountManager(accountMg), pageManager(pM) {} + + unsigned id; + pthread_t thread; + std::string nameInUrl, returnValue; + int staffel, folge, exitState; + Settings * settings; + AccountManager * accountManager; + PageManager * pageManager; + + void * setState(int state) { + this->exitState = state; + return nullptr; + } + void setData(int staffel, int folge) { this->staffel = staffel; this->folge = folge; } + +}; + + class ProgramManager { @@ -24,9 +48,13 @@ private: int infoModus(Settings * settings); PageManager pageManager; + std::vector threadList; + unsigned nextThread; int convertLink(std::string redirectLink, AccountManager *accountManager, Settings * settings, int Staffel = -1, int Folge = -1, std::string allLinks = "NOT_EMPTY"); int searchModus_update(Settings * settings); + int waitForThreads(); + }; diff --git a/pageManager.h b/pageManager.h index 679b8d4..632ab72 100644 --- a/pageManager.h +++ b/pageManager.h @@ -3,7 +3,9 @@ #include "accountManager.h" -#include + +#include "curl/curl.h" + #include #include #include diff --git a/parameterManager.cpp b/parameterManager.cpp index f39b166..295aa25 100644 --- a/parameterManager.cpp +++ b/parameterManager.cpp @@ -914,7 +914,7 @@ std::string getexepath() return std::string( result, (count > 0) ? static_cast(count) : 0 ); #endif #ifdef ABC ///_WIN32 - wchar_t result[ MAX_PATH ]; + //wchar_t result[ MAX_PATH ]; char buffer[MAX_PATH]; return std::string( result, GetModuleFileName( NULL, buffer, MAX_PATH ) ); //GetModuleFileName(NULL, result, MAX_PATH) ;