diff --git a/S_New4.pro b/S_New4.pro index 4fad636..67761ac 100644 --- a/S_New4.pro +++ b/S_New4.pro @@ -1,8 +1,8 @@ QT -= gui -#LIBS += -lcurl +LIBS += -lcurl #LIBS += -LC:\Users\Markus\Desktop\S_New4\S_New4\curl -lcurl -LIBS += -L/home/markus/Qt/S_New4/curl -lcurl +#LIBS += -L/home/markus/Qt/S_New4/curl -lcurl CONFIG += c++11 console diff --git a/accountManager.cpp b/accountManager.cpp index d752946..b2cf290 100644 --- a/accountManager.cpp +++ b/accountManager.cpp @@ -66,7 +66,29 @@ int AccountManager::writeDefault(std::string path) std::cout << "Erstelle Datei mit Accounts unter: " << path << "..." < 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 +85,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; diff --git a/pageManager.h b/pageManager.h index 5e41e2c..679b8d4 100644 --- a/pageManager.h +++ b/pageManager.h @@ -1,16 +1,14 @@ #ifndef MANAGEPAGE_H #define MANAGEPAGE_H -#include -// if complied for windows; everything is in */projectfolder/curl/ +#include "accountManager.h" + #include #include #include #include - #include -#include "accountManager.h" struct Reply { Reply() {} diff --git a/parameterManager.cpp b/parameterManager.cpp index 2367128..5a87db0 100644 --- a/parameterManager.cpp +++ b/parameterManager.cpp @@ -4,7 +4,6 @@ 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) ); @@ -33,7 +32,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,6 +65,11 @@ 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; @@ -80,7 +84,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 +110,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 +122,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) == "") @@ -219,18 +226,31 @@ int unterOption_default(Settings *settings, int argc, char ** argv) if(settings->debugMode) 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; 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 +332,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 +350,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; @@ -697,3 +723,44 @@ 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)); +} + +void unterOption_clean(Settings * settings, int argc, char **argv) +{ + if(argc > 1) + if(strcmp(argv[1], "--help") == 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 << "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 << "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; +} diff --git a/parameterManager.h b/parameterManager.h index 2d2f23c..e48b17b 100644 --- a/parameterManager.h +++ b/parameterManager.h @@ -36,7 +36,7 @@ struct Settings { proxy_ip = "127.0.0.1", languages = "GerDub,GerSub,Eng", genaueHoster = "Vivo,GoUnlimited", - version = "2.1.2", + version = "2.2.0", outputFilePath = "", default_checkDirPath = "", default_Searchmuster = "S%Staffel%E%Folge%"; @@ -53,6 +53,7 @@ struct Settings { proxy_port = 9050, default_maxDirs = 20; char pathSymbol = '/'; + unsigned maxThreads = 0; }; @@ -80,5 +81,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/programManager.cpp b/programManager.cpp index ef60211..ff3ec41 100644 --- a/programManager.cpp +++ b/programManager.cpp @@ -1,13 +1,19 @@ #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) @@ -30,6 +36,77 @@ int ProgramManager::start(Settings *settings) } } +void * threadFunction(void * KA) { + ka * myka = reinterpret_cast(KA); + myka->returnValue=""; + myka->exitState=0; + + + + Reply tmp_reply = myka->pageManager->getServerRequest(myka->pageManager->UrlPraefix + myka->nameInUrl + "/staffel-" + std::to_string(myka->staffel) + "/episode-" + std::to_string(myka->folge)); + if(tmp_reply.html == "-1") + return myka->setState(10); + std::string allLinks = myka->pageManager->getLinks(tmp_reply.html); + std::string Link = myka->pageManager->chooseHosterLink(allLinks, myka->settings->genaueHoster, myka->settings->languages); + + if(myka->settings->debugMode) + std::cout << " > Thread " << myka->id << allLinks << std::endl << ( (Link == "") ? "" : " -> Link: 'https://s.to") << Link << ( (Link == "") ? "" : "'\n" ); + + + + + std::string folgenID = std::string((myka->staffel == -1 || myka->folge == -1 ) ? "" : "S" + std::string( (myka->staffel < 10) ? "0" : "" ) + std::to_string(myka->staffel) + + "E" + std::string( (myka->folge < 10) ? "0" : "" ) + std::to_string( myka->folge ) ); + std::string green = ((myka->settings->colorless) ? "" : "\033[32m"), + red = ((myka->settings->colorless) ? "" : "\033[31m"), + orange =((myka->settings->colorless) ? "" : "\033[33m"), + blue = ((myka->settings->colorless) ? "" : "\033[34m"); + + if(Link == "") { + if(allLinks == "") { + myka->returnValue = " => " + red + "KEINEN Hoster für die Folge " + folgenID + " gefunden." + "\033[0m"; + if(myka->pageManager->writeToFile(myka->settings->outputFilePath, std::string("KEINEN Hoster für die Folge ") + folgenID + std::string(" gefunden.")) != 0) + return myka->setState(14); + } + else { + myka->returnValue = " => " + orange + "Keinen PASSENDEN Hoster für die Folge " + folgenID + " gefunden." + "\033[0m" + "\n" + + "Alle Links:" + "\n" + + myka->pageManager->replace( myka->pageManager->replace( myka->pageManager->replace( allLinks, "data-lang-key=\"1\"", "language=\"GerDub\"" ), + "data-lang-key=\"2\"", "language=\"Eng\"" ), "data-lang-key=\"3\"", "language=\"GerSub\""); + if(myka->pageManager->writeToFile(myka->settings->outputFilePath, std::string("Keinen PASSENDEN Hoster für die Folge ") + folgenID + std::string(" gefunden.")) != 0) + return myka->setState(15); + } + return myka->setState(0); + } + + for (int i = 1; i <= 3; ++i) { + std::string newUrl = myka->pageManager->getUrlAfterRedirect("https://s.to" + Link); + if (newUrl == "-1") { + return myka->setState(16); + } else if(newUrl.find("/s.to/redirect/") != std::string::npos ) { + if(myka->settings->debugMode) + std::cout << " > Thread " << myka->id << "Warnung: Redirect Link nach umwandlung (Capcha?) --> Neuer Account" << std::endl; + if(myka->pageManager->login(myka->accountManager->getNextAccount()) != 0) + return myka->setState(17); + continue; + + } else { + myka->returnValue = " => " + folgenID + ( (folgenID == "") ? "" : ": " ) + green + newUrl + "\033[0m"; + if(myka->settings->outputFilePath != "") + if(myka->pageManager->writeToFile(myka->settings->outputFilePath,folgenID + ( (folgenID == "") ? "" : ": " ) + newUrl) != 0) + return myka->setState(18); + return myka->setState(0); + } + } + myka->returnValue = " => " + folgenID + ( (folgenID == "") ? "" : ": " ) + red + "https://s.to" + Link + "\033[0m"; + if(myka->settings->outputFilePath != "") + if(myka->pageManager->writeToFile(myka->settings->outputFilePath, folgenID + ( (folgenID == "") ? "" : ": " ) + Link) != 0) + return myka->setState(19); + return myka->setState(0); + +} + + int ProgramManager::defaultModus(Settings *settings) { AccountManager accountManager(settings->accountFilePath, settings->accountNumberPath); @@ -81,9 +158,28 @@ 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) { + 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 )); + + ka * newKa = new ka(i, 0, nameInUrl, -1, settings, &accountManager, pm); + threadList.push_back(newKa); + } + } + + //Write Name to File if -o is set pageManager.writeToFile(settings->outputFilePath, "Name: " + settings->name); //Finde die anzahl der staffel heraus: @@ -122,21 +218,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 +274,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 +316,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) { diff --git a/programManager.h b/programManager.h index 35ac267..5673f86 100644 --- a/programManager.h +++ b/programManager.h @@ -4,10 +4,34 @@ #include "pageManager.h" #include "parameterManager.h" #include "accountManager.h" -#include - #include + #include +#include + + +struct ka +{ + ka(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(); + };