mirror of
https://github.com/Sude-/lgogdownloader.git
synced 2025-02-02 05:52:31 +01:00
Support new account page layout
This commit is contained in:
parent
21e6c6119d
commit
b5cdf10078
@ -92,9 +92,9 @@ class Downloader
|
||||
int HTTP_Login(const std::string& email, const std::string& password);
|
||||
std::vector<gameItem> getGames();
|
||||
std::vector<gameItem> getFreeGames();
|
||||
std::vector<gameFile> getExtrasFromHTML(const std::string& html, const std::string& gamename, const std::string& gameid);
|
||||
std::string getGameDetailsHTML(const std::string& gamename, const std::string& gameid);
|
||||
std::string getSerialsFromHTML(const std::string& html);
|
||||
std::vector<gameFile> getExtrasFromJSON(const Json::Value& json, const std::string& gamename);
|
||||
Json::Value getGameDetailsJSON(const std::string& gameid);
|
||||
std::string getSerialsFromJSON(const Json::Value& json);
|
||||
void saveSerials(const std::string& serials, const std::string& filepath);
|
||||
|
||||
static int progressCallback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow);
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <sstream>
|
||||
#include <rhash.h>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <json/json.h>
|
||||
|
||||
struct gameSpecificConfig
|
||||
{
|
||||
@ -37,6 +38,8 @@ namespace Util
|
||||
void filepathReplaceReservedStrings(std::string& str, const std::string& gamename, const unsigned int& platformId = 0, const std::string& dlcname = "");
|
||||
void setFilePermissions(const boost::filesystem::path& path, const boost::filesystem::perms& permissions);
|
||||
int getTerminalWidth();
|
||||
void getDownloaderUrlsFromJSON(const Json::Value &root, std::vector<std::string> &urls);
|
||||
std::vector<std::string> getDLCNamesFromJSON(const Json::Value &root);
|
||||
}
|
||||
|
||||
#endif // UTIL_H
|
||||
|
@ -261,38 +261,69 @@ int Downloader::getGameDetails()
|
||||
if (!gogAPI->getError())
|
||||
{
|
||||
game.filterWithPriorities(config);
|
||||
std::string gameDetailsHTML;
|
||||
Json::Value gameDetailsJSON;
|
||||
|
||||
if (game.extras.empty() && config.bExtras) // Try to get extras from account page if API didn't return any extras
|
||||
{
|
||||
gameDetailsHTML = this->getGameDetailsHTML(gameItems[i].name, gameItems[i].id);
|
||||
game.extras = this->getExtrasFromHTML(gameDetailsHTML, gameItems[i].name, gameItems[i].id);
|
||||
gameDetailsJSON = this->getGameDetailsJSON(gameItems[i].id);
|
||||
game.extras = this->getExtrasFromJSON(gameDetailsJSON, gameItems[i].name);
|
||||
}
|
||||
if (config.bSaveSerials)
|
||||
{
|
||||
if (gameDetailsHTML.empty())
|
||||
gameDetailsHTML = this->getGameDetailsHTML(gameItems[i].name, gameItems[i].id);
|
||||
game.serials = this->getSerialsFromHTML(gameDetailsHTML);
|
||||
if (gameDetailsJSON.empty())
|
||||
gameDetailsJSON = this->getGameDetailsJSON(gameItems[i].id);
|
||||
game.serials = this->getSerialsFromJSON(gameDetailsJSON);
|
||||
}
|
||||
if (game.dlcs.empty() && bHasDLC && conf.bDLC)
|
||||
{
|
||||
if (gameDetailsJSON.empty())
|
||||
gameDetailsJSON = this->getGameDetailsJSON(gameItems[i].id);
|
||||
|
||||
for (unsigned int j = 0; j < gameItems[i].dlcnames.size(); ++j)
|
||||
{
|
||||
gameDetails dlc;
|
||||
std::string gameDetailsHTML_dlc;
|
||||
dlc = gogAPI->getGameDetails(gameItems[i].dlcnames[j], conf.iInstallerType, conf.iInstallerLanguage, config.bDuplicateHandler);
|
||||
dlc.filterWithPriorities(config);
|
||||
if (dlc.extras.empty() && config.bExtras) // Try to get extras from account page if API didn't return any extras
|
||||
{
|
||||
gameDetailsHTML_dlc = this->getGameDetailsHTML(gameItems[i].dlcnames[j], gameItems[i].id);
|
||||
dlc.extras = this->getExtrasFromHTML(gameDetailsHTML_dlc, gameItems[i].dlcnames[j], gameItems[i].id);
|
||||
// Make sure we get extras for the right DLC
|
||||
for (unsigned int k = 0; k < gameDetailsJSON["dlcs"].size(); ++k)
|
||||
{
|
||||
std::vector<std::string> urls;
|
||||
if (gameDetailsJSON["dlcs"][k].isMember("extras"))
|
||||
Util::getDownloaderUrlsFromJSON(gameDetailsJSON["dlcs"][k]["extras"], urls);
|
||||
|
||||
if (!urls.empty())
|
||||
{
|
||||
if (urls[0].find("/" + gameItems[i].dlcnames[j] + "/") != std::string::npos)
|
||||
{
|
||||
dlc.extras = this->getExtrasFromJSON(gameDetailsJSON["dlcs"][k], gameItems[i].dlcnames[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (config.bSaveSerials)
|
||||
{
|
||||
if (gameDetailsHTML_dlc.empty())
|
||||
gameDetailsHTML_dlc = this->getGameDetailsHTML(gameItems[i].dlcnames[j], gameItems[i].id);
|
||||
dlc.serials = this->getSerialsFromHTML(gameDetailsHTML_dlc);
|
||||
// Make sure we save serial for the right DLC
|
||||
for (unsigned int k = 0; k < gameDetailsJSON["dlcs"].size(); ++k)
|
||||
{
|
||||
std::vector<std::string> urls;
|
||||
if (gameDetailsJSON["dlcs"][k].isMember("cdKey") && gameDetailsJSON["dlcs"][k].isMember("downloads"))
|
||||
{
|
||||
// Assuming that only DLC with installers can have serial
|
||||
Util::getDownloaderUrlsFromJSON(gameDetailsJSON["dlcs"][k]["downloads"], urls);
|
||||
}
|
||||
|
||||
if (!urls.empty())
|
||||
{
|
||||
if (urls[0].find("/" + gameItems[i].dlcnames[j] + "/") != std::string::npos)
|
||||
{
|
||||
dlc.serials = this->getSerialsFromJSON(gameDetailsJSON["dlcs"][k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
game.dlcs.push_back(dlc);
|
||||
}
|
||||
}
|
||||
@ -1970,75 +2001,36 @@ int Downloader::HTTP_Login(const std::string& email, const std::string& password
|
||||
std::cout << curl_easy_strerror(result) << std::endl;
|
||||
}
|
||||
|
||||
html = this->getResponse("https://www.gog.com/account/settings");
|
||||
html = this->getResponse("https://www.gog.com/account/settings/personal");
|
||||
|
||||
std::string account_email, username;
|
||||
std::string email_lowercase = boost::algorithm::to_lower_copy(email); // boost::algorithm::to_lower does in-place modification but "email" is read-only so we need to make a copy of it
|
||||
dom = parser.parseTree(html);
|
||||
it = dom.begin();
|
||||
end = dom.end();
|
||||
bool bEmailFound = false;
|
||||
bool bUsernameFound = false;
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
if (it->tagName()=="input")
|
||||
if (it->tagName()=="strong")
|
||||
{
|
||||
it->parseAttributes();
|
||||
if (it->attribute("id").second == "accountEditEmail")
|
||||
{
|
||||
account_email = it->attribute("value").second;
|
||||
bEmailFound = true;
|
||||
}
|
||||
}
|
||||
else if (it->tagName()=="span")
|
||||
{
|
||||
it->parseAttributes();
|
||||
if (it->attribute("class").second == "nickname")
|
||||
if (it->attribute("class").second == "settings-item__value settings-item__section")
|
||||
{
|
||||
for (unsigned int i = 0; i < dom.number_of_children(it); ++i)
|
||||
{
|
||||
tree<htmlcxx::HTML::Node>::iterator nick_it = dom.child(it, i);
|
||||
if (!nick_it->isTag() && !nick_it->isComment())
|
||||
tree<htmlcxx::HTML::Node>::iterator tag_it = dom.child(it, i);
|
||||
if (!tag_it->isTag() && !tag_it->isComment())
|
||||
{
|
||||
username = nick_it->text();
|
||||
bUsernameFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bUsernameFound && bEmailFound)
|
||||
break;
|
||||
}
|
||||
|
||||
// Convert to lowercase for comparison
|
||||
std::string email_lowercase = boost::algorithm::to_lower_copy(email); // boost::algorithm::to_lower does in-place modification but "email" is read-only so we need to make a copy of it
|
||||
boost::algorithm::to_lower(account_email);
|
||||
boost::algorithm::to_lower(username);
|
||||
|
||||
if (email_lowercase == account_email || email_lowercase == username)
|
||||
std::string tag_text = boost::algorithm::to_lower_copy(tag_it->text());
|
||||
if (tag_text == email_lowercase)
|
||||
{
|
||||
res = 1; // Login successful
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef DEBUG
|
||||
std::cerr << "DEBUG INFO (Downloader::HTTP_Login)" << std::endl;
|
||||
if (!bEmailFound || !bUsernameFound)
|
||||
{
|
||||
if (!bEmailFound)
|
||||
std::cerr << "Could not find \"accountEditEmail\" input field on account settings page." << std::endl;
|
||||
if (!bUsernameFound)
|
||||
std::cerr << "Could not find username on account settings page." << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (email_lowercase != account_email)
|
||||
std::cerr << "Email (" << email_lowercase << ") doesn't match account email (" << account_email << ")" << std::endl;
|
||||
if (email_lowercase != username)
|
||||
std::cerr << "Username (" << email_lowercase << ") doesn't match account username (" << username << ")" << std::endl;
|
||||
}
|
||||
#endif
|
||||
res = 0; // Login failed
|
||||
}
|
||||
}
|
||||
if (res == 1) // Login was successful so no need to go through the remaining tags
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
@ -2051,12 +2043,11 @@ std::vector<gameItem> Downloader::getGames()
|
||||
Json::Value root;
|
||||
Json::Reader *jsonparser = new Json::Reader;
|
||||
int i = 1;
|
||||
std::string html = "";
|
||||
std::string page_html = "";
|
||||
bool bAllPagesParsed = false;
|
||||
|
||||
do
|
||||
{
|
||||
std::string response = this->getResponse("https://www.gog.com/account/ajax?a=gamesShelfMore&s=title&q=&t=0&p=" + std::to_string(i));
|
||||
std::string response = this->getResponse("https://www.gog.com/account/getFilteredProducts?hasHiddenProducts=false&hiddenFlag=0&isUpdated=0&mediaType=1&sortBy=title&system=&page=" + std::to_string(i));
|
||||
|
||||
// Parse JSON
|
||||
if (!jsonparser->parse(response, root))
|
||||
@ -2071,163 +2062,61 @@ std::vector<gameItem> Downloader::getGames()
|
||||
#ifdef DEBUG
|
||||
std::cerr << "DEBUG INFO (Downloader::getGames)" << std::endl << root << std::endl;
|
||||
#endif
|
||||
page_html = root["html"].asString();
|
||||
html += page_html;
|
||||
if (page_html.empty() && i == 1)
|
||||
if (root["page"].asInt() == root["totalPages"].asInt())
|
||||
bAllPagesParsed = true;
|
||||
if (root["products"].isArray())
|
||||
{
|
||||
std::cout << "No games were found on your account. Try --login to refresh your authorization." << std::endl;
|
||||
}
|
||||
i++;
|
||||
} while (!page_html.empty());
|
||||
|
||||
delete jsonparser;
|
||||
|
||||
// Parse HTML to get game names
|
||||
htmlcxx::HTML::ParserDom parser;
|
||||
tree<htmlcxx::HTML::Node> dom = parser.parseTree(html);
|
||||
tree<htmlcxx::HTML::Node>::iterator it = dom.begin();
|
||||
tree<htmlcxx::HTML::Node>::iterator end = dom.end();
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
if (it->tagName()=="div")
|
||||
{
|
||||
it->parseAttributes();
|
||||
std::string classname = it->attribute("class").second;
|
||||
if (classname=="shelf_game")
|
||||
for (unsigned int i = 0; i < root["products"].size(); ++i)
|
||||
{
|
||||
Json::Value product = root["products"][i];
|
||||
gameItem game;
|
||||
// Game name is contained in data-gameindex attribute
|
||||
game.name = it->attribute("data-gameindex").second;
|
||||
game.id = it->attribute("data-gameid").second;
|
||||
game.name = product["slug"].asString();
|
||||
game.id = product["id"].asString();
|
||||
|
||||
// Get platform info
|
||||
std::string tags = it->attribute("data-title").second;
|
||||
unsigned int platform = GlobalConstants::PLATFORM_WINDOWS; // The tags don't specify Windows support so assume that there's always a Windows version
|
||||
|
||||
if (tags.find("linux") != std::string::npos)
|
||||
platform |= GlobalConstants::PLATFORM_LINUX;
|
||||
if (tags.find("osx mac") != std::string::npos)
|
||||
unsigned int platform = 0;
|
||||
if (product["worksOn"]["Windows"].asBool())
|
||||
platform |= GlobalConstants::PLATFORM_WINDOWS;
|
||||
if (product["worksOn"]["Mac"].asBool())
|
||||
platform |= GlobalConstants::PLATFORM_MAC;
|
||||
if (product["worksOn"]["Linux"].asBool())
|
||||
platform |= GlobalConstants::PLATFORM_LINUX;
|
||||
|
||||
// Skip if platform doesn't match
|
||||
if (config.bPlatformDetection && !(platform & config.iInstallerType))
|
||||
continue;
|
||||
|
||||
if (!game.name.empty() && !game.id.empty())
|
||||
{
|
||||
// Check for DLC
|
||||
if (config.bDLC)
|
||||
{
|
||||
tree<htmlcxx::HTML::Node>::iterator dlc_it = it;
|
||||
tree<htmlcxx::HTML::Node>::iterator dlc_end = it.end();
|
||||
for (; dlc_it != dlc_end; ++dlc_it)
|
||||
int dlcCount = product["dlcCount"].asInt();
|
||||
if (dlcCount != 0)
|
||||
{
|
||||
if (dlc_it->tagName()=="div")
|
||||
{
|
||||
dlc_it->parseAttributes();
|
||||
std::string classname_dlc = dlc_it->attribute("class").second;
|
||||
if (classname_dlc == "shelf-game-dlc-counter")
|
||||
{
|
||||
std::string content;
|
||||
for (unsigned int i = 0; i < dom.number_of_children(dlc_it); ++i)
|
||||
{
|
||||
tree<htmlcxx::HTML::Node>::iterator it = dom.child(dlc_it, i);
|
||||
if (!it->isTag() && !it->isComment())
|
||||
content += it->text();
|
||||
}
|
||||
// Get game names if game has DLC
|
||||
if (content.find("DLC")!=std::string::npos)
|
||||
{
|
||||
Json::Value root;
|
||||
Json::Reader *jsonparser = new Json::Reader;
|
||||
|
||||
std::string gameDataUrl = "https://www.gog.com/account/ajax?a=gamesListDetails&g=" + game.id;
|
||||
std::string json = this->getResponse(gameDataUrl);
|
||||
// Parse JSON
|
||||
if (!jsonparser->parse(json, root))
|
||||
std::string gameinfo = this->getResponse("https://www.gog.com/account/gameDetails/" + game.id + ".json");
|
||||
Json::Value info;
|
||||
if (!jsonparser->parse(gameinfo, info))
|
||||
{
|
||||
#ifdef DEBUG
|
||||
std::cerr << "DEBUG INFO (Downloader::getGames)" << std::endl << json << std::endl;
|
||||
std::cerr << "DEBUG INFO (Downloader::getGames)" << std::endl << gameinfo << std::endl;
|
||||
#endif
|
||||
std::cout << jsonparser->getFormatedErrorMessages();
|
||||
delete jsonparser;
|
||||
exit(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef DEBUG
|
||||
std::cerr << "DEBUG INFO (Downloader::getGames)" << std::endl << root << std::endl;
|
||||
std::cerr << "DEBUG INFO (Downloader::getGames)" << std::endl << info << std::endl;
|
||||
#endif
|
||||
std::string html = root["details"]["html"].asString();
|
||||
delete jsonparser;
|
||||
|
||||
// Parse HTML to get game names for DLC
|
||||
htmlcxx::HTML::ParserDom parser;
|
||||
tree<htmlcxx::HTML::Node> dom = parser.parseTree(html);
|
||||
tree<htmlcxx::HTML::Node>::iterator it = dom.begin();
|
||||
tree<htmlcxx::HTML::Node>::iterator end = dom.end();
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
if (it->tagName()=="div")
|
||||
{
|
||||
it->parseAttributes();
|
||||
std::string gamename = it->attribute("data-gameindex").second;
|
||||
if (!gamename.empty() && gamename!=game.name)
|
||||
{
|
||||
bool bDuplicate = false;
|
||||
for (unsigned int i = 0; i < game.dlcnames.size(); ++i)
|
||||
{
|
||||
if (gamename == game.dlcnames[i])
|
||||
{
|
||||
bDuplicate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!bDuplicate)
|
||||
game.dlcnames.push_back(gamename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try getting game names for DLCs from extra links. Catches game names for DLCs that don't have installers.
|
||||
it = dom.begin();
|
||||
end = dom.end();
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
if (it->tagName()=="a")
|
||||
{
|
||||
it->parseAttributes();
|
||||
std::string href = it->attribute("href").second;
|
||||
std::string search_string = "/downlink/file/"; // Extra links: https://www.gog.com/downlink/file/gamename/id_number
|
||||
if (href.find(search_string)!=std::string::npos)
|
||||
{
|
||||
std::string gamename;
|
||||
gamename.assign(href.begin()+href.find(search_string)+search_string.length(), href.begin()+href.find_last_of("/"));
|
||||
if (!gamename.empty() && gamename!=game.name)
|
||||
{
|
||||
bool bDuplicate = false;
|
||||
for (unsigned int i = 0; i < game.dlcnames.size(); ++i)
|
||||
{
|
||||
if (gamename == game.dlcnames[i])
|
||||
{
|
||||
bDuplicate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!bDuplicate)
|
||||
game.dlcnames.push_back(gamename);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
game.dlcnames = Util::getDLCNamesFromJSON(info["dlcs"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
games.push_back(game);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
i++;
|
||||
} while (!bAllPagesParsed);
|
||||
|
||||
delete jsonparser;
|
||||
|
||||
return games;
|
||||
}
|
||||
@ -2267,9 +2156,9 @@ std::vector<gameItem> Downloader::getFreeGames()
|
||||
return games;
|
||||
}
|
||||
|
||||
std::string Downloader::getGameDetailsHTML(const std::string& gamename, const std::string& gameid)
|
||||
Json::Value Downloader::getGameDetailsJSON(const std::string& gameid)
|
||||
{
|
||||
std::string gameDataUrl = "https://www.gog.com/account/ajax?a=gamesListDetails&g=" + gameid;
|
||||
std::string gameDataUrl = "https://www.gog.com/account/gameDetails/" + gameid + ".json";
|
||||
std::string json = this->getResponse(gameDataUrl);
|
||||
|
||||
// Parse JSON
|
||||
@ -2278,40 +2167,33 @@ std::string Downloader::getGameDetailsHTML(const std::string& gamename, const st
|
||||
if (!jsonparser->parse(json, root))
|
||||
{
|
||||
#ifdef DEBUG
|
||||
std::cerr << "DEBUG INFO (Downloader::getGameDetailsHTML)" << std::endl << json << std::endl;
|
||||
std::cerr << "DEBUG INFO (Downloader::getGameDetailsJSON)" << std::endl << json << std::endl;
|
||||
#endif
|
||||
std::cout << jsonparser->getFormatedErrorMessages();
|
||||
delete jsonparser;
|
||||
exit(1);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
std::cerr << "DEBUG INFO (Downloader::getGameDetailsHTML)" << std::endl << root << std::endl;
|
||||
std::cerr << "DEBUG INFO (Downloader::getGameDetailsJSON)" << std::endl << root << std::endl;
|
||||
#endif
|
||||
std::string html = root["details"]["html"].asString();
|
||||
delete jsonparser;
|
||||
|
||||
return html;
|
||||
return root;
|
||||
}
|
||||
|
||||
std::vector<gameFile> Downloader::getExtrasFromHTML(const std::string& html, const std::string& gamename, const std::string& gameid)
|
||||
std::vector<gameFile> Downloader::getExtrasFromJSON(const Json::Value& json, const std::string& gamename)
|
||||
{
|
||||
std::vector<gameFile> extras;
|
||||
|
||||
htmlcxx::HTML::ParserDom parser;
|
||||
tree<htmlcxx::HTML::Node> dom = parser.parseTree(html);
|
||||
tree<htmlcxx::HTML::Node>::iterator it = dom.begin();
|
||||
tree<htmlcxx::HTML::Node>::iterator end = dom.end();
|
||||
for (; it != end; ++it)
|
||||
std::vector<std::string> downloaderUrls;
|
||||
Util::getDownloaderUrlsFromJSON(json["extras"], downloaderUrls);
|
||||
|
||||
for (unsigned int i = 0; i < json["extras"].size(); ++i)
|
||||
{
|
||||
if (it->tagName()=="a")
|
||||
{
|
||||
it->parseAttributes();
|
||||
std::string href = it->attribute("href").second;
|
||||
// Extra links https://www.gog.com/downlink/file/gamename/id_number
|
||||
if (href.find("/downlink/file/" + gamename + "/")!=std::string::npos)
|
||||
{
|
||||
std::string id, name, path;
|
||||
id.assign(href.begin()+href.find_last_of("/")+1, href.end());
|
||||
std::string id, name, path, downloaderUrl;
|
||||
name = json["extras"][i]["name"].asString();
|
||||
downloaderUrl = json["extras"][i]["downloaderUrl"].asString();
|
||||
id.assign(downloaderUrl.begin()+downloaderUrl.find_last_of("/")+1, downloaderUrl.end());
|
||||
|
||||
// Get path from download link
|
||||
std::string url = gogAPI->getExtraLink(gamename, id);
|
||||
@ -2327,14 +2209,15 @@ std::vector<gameFile> Downloader::getExtrasFromHTML(const std::string& html, con
|
||||
path = "/" + gamename + "/extras/" + path;
|
||||
}
|
||||
|
||||
// Get name from path
|
||||
// Get name from path if name was not specified
|
||||
if (name.empty())
|
||||
name.assign(path.begin()+path.find_last_of("/")+1,path.end());
|
||||
|
||||
if (name.empty())
|
||||
{
|
||||
#ifdef DEBUG
|
||||
std::cerr << "DEBUG INFO (getExtrasFromHTML)" << std::endl;
|
||||
std::cerr << "Skipped file without a name (game: " << gamename << ", gameid: " << gameid << ", fileid: " << id << ")" << std::endl;
|
||||
std::cerr << "DEBUG INFO (getExtrasFromJSON)" << std::endl;
|
||||
std::cerr << "Skipped file without a name (game: " << gamename << ", fileid: " << id << ")" << std::endl;
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
@ -2348,47 +2231,36 @@ std::vector<gameFile> Downloader::getExtrasFromHTML(const std::string& html, con
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return extras;
|
||||
}
|
||||
|
||||
|
||||
std::string Downloader::getSerialsFromHTML(const std::string& html)
|
||||
std::string Downloader::getSerialsFromJSON(const Json::Value& json)
|
||||
{
|
||||
std::ostringstream serials;
|
||||
|
||||
std::string cdkey = json["cdKey"].asString();
|
||||
if (cdkey.find("<span>") == std::string::npos)
|
||||
{
|
||||
serials << cdkey;
|
||||
}
|
||||
else
|
||||
{
|
||||
htmlcxx::HTML::ParserDom parser;
|
||||
tree<htmlcxx::HTML::Node> dom = parser.parseTree(html);
|
||||
tree<htmlcxx::HTML::Node> dom = parser.parseTree(cdkey);
|
||||
tree<htmlcxx::HTML::Node>::iterator it = dom.begin();
|
||||
tree<htmlcxx::HTML::Node>::iterator end = dom.end();
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
if (it->tagName() == "div")
|
||||
{
|
||||
it->parseAttributes();
|
||||
std::string classname = it->attribute("class").second;
|
||||
if (classname == "list_serial_h")
|
||||
{
|
||||
for (unsigned int i = 0; i < dom.number_of_children(it); ++i)
|
||||
{
|
||||
tree<htmlcxx::HTML::Node>::iterator serials_it = dom.child(it, i);
|
||||
if (!serials_it->isComment())
|
||||
{
|
||||
std::string tag_text;
|
||||
if (!serials_it->isTag())
|
||||
if (it->tagName() == "span")
|
||||
{
|
||||
if (!serials_it->text().empty())
|
||||
tag_text = serials_it->text();
|
||||
}
|
||||
else if (serials_it->tagName() == "span")
|
||||
for (unsigned int j = 0; j < dom.number_of_children(it); ++j)
|
||||
{
|
||||
for (unsigned int j = 0; j < dom.number_of_children(serials_it); ++j)
|
||||
{
|
||||
tree<htmlcxx::HTML::Node>::iterator serials_span_it = dom.child(serials_it, j);
|
||||
if (!serials_span_it->isTag() && !serials_span_it->isComment())
|
||||
tag_text = serials_span_it->text();
|
||||
tree<htmlcxx::HTML::Node>::iterator span_it = dom.child(it, j);
|
||||
if (!span_it->isTag() && !span_it->isComment())
|
||||
tag_text = span_it->text();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2401,9 +2273,6 @@ std::string Downloader::getSerialsFromHTML(const std::string& html)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return serials.str();
|
||||
}
|
||||
|
43
src/util.cpp
43
src/util.cpp
@ -342,3 +342,46 @@ int Util::getTerminalWidth()
|
||||
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
|
||||
return static_cast<int>(w.ws_col);
|
||||
}
|
||||
|
||||
|
||||
void Util::getDownloaderUrlsFromJSON(const Json::Value &root, std::vector<std::string> &urls)
|
||||
{
|
||||
if(root.size() > 0) {
|
||||
for(Json::ValueIterator it = root.begin() ; it != root.end() ; ++it)
|
||||
{
|
||||
if (it.key() == "downloaderUrl")
|
||||
urls.push_back(it->asString());
|
||||
else
|
||||
getDownloaderUrlsFromJSON(*it, urls);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::string> Util::getDLCNamesFromJSON(const Json::Value &root)
|
||||
{
|
||||
std::vector<std::string> urls, dlcnames;
|
||||
getDownloaderUrlsFromJSON(root, urls);
|
||||
|
||||
for (unsigned int i = 0; i < urls.size(); ++i)
|
||||
{
|
||||
std::string gamename;
|
||||
std::string match_string = "gogdownloader://";
|
||||
if (urls[i].find(match_string) == std::string::npos)
|
||||
continue;
|
||||
|
||||
gamename.assign(urls[i].begin()+urls[i].find(match_string)+match_string.length(), urls[i].begin()+urls[i].find_last_of("/"));
|
||||
bool bDuplicate = false;
|
||||
for (unsigned int j = 0; j < dlcnames.size(); ++j)
|
||||
{
|
||||
if (gamename == dlcnames[j])
|
||||
{
|
||||
bDuplicate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!bDuplicate)
|
||||
dlcnames.push_back(gamename);
|
||||
}
|
||||
return dlcnames;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user