mirror of
https://github.com/Sude-/lgogdownloader.git
synced 2024-11-20 03:39:17 +01:00
Get game details using Galaxy API
Game details are now acquired using Galaxy API. Allow using most features without valid downloader API login by changing Downloader::isLoggedIn to return false only if website is not logged in. --download-file still uses old API and will not work without valid API login. Downloader::downloadFileWithId prints error message and exits if user doesn't have valid API login. Game details cache version is incremented because of changes to gameFile class. Show product id for DLCs when using --list-details option. Rewrote Downloader::repair to remove duplicated code. Fixed serials containing <br> tags.
This commit is contained in:
parent
6f42fec671
commit
706158d595
@ -11,6 +11,7 @@
|
||||
#include "globals.h"
|
||||
#include "config.h"
|
||||
#include "util.h"
|
||||
#include "gamedetails.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
@ -53,11 +54,17 @@ class galaxyAPI
|
||||
std::string getResponse(const std::string& url, const bool& zlib_decompress = false);
|
||||
std::string hashToGalaxyPath(const std::string& hash);
|
||||
std::vector<galaxyDepotItem> getDepotItemsVector(const std::string& hash);
|
||||
Json::Value getProductInfo(const std::string& product_id);
|
||||
gameDetails productInfoJsonToGameDetails(const Json::Value& json, const DownloadConfig& dlConf);
|
||||
protected:
|
||||
private:
|
||||
CurlConfig curlConf;
|
||||
static size_t writeMemoryCallback(char *ptr, size_t size, size_t nmemb, void *userp);
|
||||
CURL* curlhandle;
|
||||
std::vector<gameFile> installerJsonNodeToGameFileVector(const std::string& gamename, const Json::Value& json, const unsigned int& platform = (GlobalConstants::PLATFORM_WINDOWS | GlobalConstants::PLATFORM_LINUX), const unsigned int& lang = GlobalConstants::LANGUAGE_EN, const bool& useDuplicateHandler = false);
|
||||
std::vector<gameFile> patchJsonNodeToGameFileVector(const std::string& gamename, const Json::Value& json, const unsigned int& platform = (GlobalConstants::PLATFORM_WINDOWS | GlobalConstants::PLATFORM_LINUX), const unsigned int& lang = GlobalConstants::LANGUAGE_EN, const bool& useDuplicateHandler = false);
|
||||
std::vector<gameFile> languagepackJsonNodeToGameFileVector(const std::string& gamename, const Json::Value& json, const unsigned int& platform = (GlobalConstants::PLATFORM_WINDOWS | GlobalConstants::PLATFORM_LINUX), const unsigned int& lang = GlobalConstants::LANGUAGE_EN, const bool& useDuplicateHandler = false);
|
||||
std::vector<gameFile> extraJsonNodeToGameFileVector(const std::string& gamename, const Json::Value& json);
|
||||
};
|
||||
|
||||
#endif // GALAXYAPI_H
|
||||
|
@ -31,6 +31,7 @@ class gameFile
|
||||
std::string name;
|
||||
std::string path;
|
||||
std::string size;
|
||||
std::string galaxy_downlink_json_url;
|
||||
unsigned int platform;
|
||||
unsigned int language;
|
||||
unsigned int type;
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
namespace GlobalConstants
|
||||
{
|
||||
const int GAMEDETAILS_CACHE_VERSION = 2;
|
||||
const int GAMEDETAILS_CACHE_VERSION = 3;
|
||||
const int ZLIB_WINDOW_SIZE = 15;
|
||||
|
||||
struct optionsStruct {const unsigned int id; const std::string code; const std::string str; const std::string regexp;};
|
||||
|
@ -182,7 +182,11 @@ bool Downloader::isLoggedIn()
|
||||
if (!bIsLoggedInAPI)
|
||||
Globals::globalConfig.bLoginAPI = true;
|
||||
|
||||
if (bIsLoggedInAPI && bWebsiteIsLoggedIn)
|
||||
/* Only check that website is logged in.
|
||||
Allows users to use most of the functionality without having valid API login credentials.
|
||||
Globals::globalConfig.bLoginAPI can still be set to true at this point which means that if website is not logged in we still try to login to API.
|
||||
*/
|
||||
if (bWebsiteIsLoggedIn)
|
||||
bIsLoggedIn = true;
|
||||
|
||||
return bIsLoggedIn;
|
||||
@ -312,7 +316,7 @@ int Downloader::login()
|
||||
{
|
||||
if (!gogAPI->login(email, password))
|
||||
{
|
||||
std::cerr << "API: Login failed" << std::endl;
|
||||
std::cerr << "API: Login failed (some features may not work)" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
@ -499,7 +503,7 @@ int Downloader::listGames()
|
||||
std::cout << "gamename: " << games[i].gamename << std::endl
|
||||
<< "product id: " << games[i].product_id << std::endl
|
||||
<< "title: " << games[i].title << std::endl
|
||||
<< "icon: " << "http://static.gog.com" << games[i].icon << std::endl;
|
||||
<< "icon: " << games[i].icon << std::endl;
|
||||
if (!games[i].serials.empty())
|
||||
std::cout << "serials:" << std::endl << games[i].serials << std::endl;
|
||||
|
||||
@ -620,6 +624,7 @@ int Downloader::listGames()
|
||||
}
|
||||
|
||||
std::cout << "\tgamename: " << games[i].dlcs[j].gamename << std::endl
|
||||
<< "\tproduct id: " << games[i].dlcs[j].product_id << std::endl
|
||||
<< "\tid: " << games[i].dlcs[j].installers[k].id << std::endl
|
||||
<< "\tname: " << games[i].dlcs[j].installers[k].name << std::endl
|
||||
<< "\tpath: " << games[i].dlcs[j].installers[k].path << std::endl
|
||||
@ -637,6 +642,7 @@ int Downloader::listGames()
|
||||
}
|
||||
|
||||
std::cout << "\tgamename: " << games[i].dlcs[j].gamename << std::endl
|
||||
<< "\tproduct id: " << games[i].dlcs[j].product_id << std::endl
|
||||
<< "\tid: " << games[i].dlcs[j].patches[k].id << std::endl
|
||||
<< "\tname: " << games[i].dlcs[j].patches[k].name << std::endl
|
||||
<< "\tpath: " << games[i].dlcs[j].patches[k].path << std::endl
|
||||
@ -653,6 +659,7 @@ int Downloader::listGames()
|
||||
}
|
||||
|
||||
std::cout << "\tgamename: " << games[i].dlcs[j].gamename << std::endl
|
||||
<< "\tproduct id: " << games[i].dlcs[j].product_id << std::endl
|
||||
<< "\tid: " << games[i].dlcs[j].extras[k].id << std::endl
|
||||
<< "\tname: " << games[i].dlcs[j].extras[k].name << std::endl
|
||||
<< "\tpath: " << games[i].dlcs[j].extras[k].path << std::endl
|
||||
@ -669,6 +676,7 @@ int Downloader::listGames()
|
||||
}
|
||||
|
||||
std::cout << "\tgamename: " << games[i].dlcs[j].gamename << std::endl
|
||||
<< "\tproduct id: " << games[i].dlcs[j].product_id << std::endl
|
||||
<< "\tid: " << games[i].dlcs[j].languagepacks[k].id << std::endl
|
||||
<< "\tname: " << games[i].dlcs[j].languagepacks[k].name << std::endl
|
||||
<< "\tpath: " << games[i].dlcs[j].languagepacks[k].path << std::endl
|
||||
@ -707,283 +715,86 @@ void Downloader::repair()
|
||||
if (this->games.empty())
|
||||
this->getGameDetails();
|
||||
|
||||
Json::Reader *jsonparser = new Json::Reader;
|
||||
|
||||
// Create a vector containing all game files
|
||||
std::vector<gameFile> vGameFiles;
|
||||
for (unsigned int i = 0; i < games.size(); ++i)
|
||||
{
|
||||
// Installers (use remote or local file)
|
||||
if (Globals::globalConfig.dlConf.bInstallers)
|
||||
std::vector<gameFile> vec = games[i].getGameFileVector();
|
||||
vGameFiles.insert(std::end(vGameFiles), std::begin(vec), std::end(vec));
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < vGameFiles.size(); ++i)
|
||||
{
|
||||
gameSpecificConfig conf;
|
||||
conf.dlConf = Globals::globalConfig.dlConf;
|
||||
conf.dirConf = Globals::globalConfig.dirConf;
|
||||
|
||||
unsigned int type = vGameFiles[i].type;
|
||||
if (!conf.dlConf.bDLC && (type & GFTYPE_DLC))
|
||||
continue;
|
||||
if (!conf.dlConf.bInstallers && (type & GFTYPE_INSTALLER))
|
||||
continue;
|
||||
if (!conf.dlConf.bExtras && (type & GFTYPE_EXTRA))
|
||||
continue;
|
||||
if (!conf.dlConf.bPatches && (type & GFTYPE_PATCH))
|
||||
continue;
|
||||
if (!conf.dlConf.bLanguagePacks && (type & GFTYPE_LANGPACK))
|
||||
continue;
|
||||
|
||||
std::string filepath = vGameFiles[i].getFilepath();
|
||||
if (Globals::globalConfig.blacklist.isBlacklisted(filepath))
|
||||
{
|
||||
for (unsigned int j = 0; j < games[i].installers.size(); ++j)
|
||||
{
|
||||
std::string filepath = games[i].installers[j].getFilepath();
|
||||
if (Globals::globalConfig.blacklist.isBlacklisted(filepath))
|
||||
{
|
||||
if (Globals::globalConfig.bVerbose)
|
||||
std::cerr << "skipped blacklisted file " << filepath << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get XML data
|
||||
std::string XML = "";
|
||||
if (Globals::globalConfig.dlConf.bRemoteXML)
|
||||
{
|
||||
XML = gogAPI->getXML(games[i].gamename, games[i].installers[j].id);
|
||||
if (gogAPI->getError())
|
||||
{
|
||||
std::cerr << gogAPI->getErrorMessage() << std::endl;
|
||||
gogAPI->clearError();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Repair
|
||||
bool bUseLocalXML = !Globals::globalConfig.dlConf.bRemoteXML;
|
||||
if (!XML.empty() || bUseLocalXML)
|
||||
{
|
||||
std::string url = gogAPI->getInstallerLink(games[i].gamename, games[i].installers[j].id);
|
||||
if (gogAPI->getError())
|
||||
{
|
||||
std::cerr << gogAPI->getErrorMessage() << std::endl;
|
||||
gogAPI->clearError();
|
||||
continue;
|
||||
}
|
||||
std::cout << "Repairing file " << filepath << std::endl;
|
||||
this->repairFile(url, filepath, XML, games[i].gamename);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
if (Globals::globalConfig.bVerbose)
|
||||
std::cerr << "skipped blacklisted file " << filepath << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Extras (GOG doesn't provide XML data for extras, use local file)
|
||||
if (Globals::globalConfig.dlConf.bExtras)
|
||||
{
|
||||
for (unsigned int j = 0; j < games[i].extras.size(); ++j)
|
||||
{
|
||||
std::string filepath = games[i].extras[j].getFilepath();
|
||||
if (Globals::globalConfig.blacklist.isBlacklisted(filepath))
|
||||
{
|
||||
if (Globals::globalConfig.bVerbose)
|
||||
std::cerr << "skipped blacklisted file " << filepath << std::endl;
|
||||
continue;
|
||||
}
|
||||
Json::Value downlinkJson;
|
||||
std::string response = gogGalaxy->getResponse(vGameFiles[i].galaxy_downlink_json_url);
|
||||
|
||||
std::string url = gogAPI->getExtraLink(games[i].gamename, games[i].extras[j].id);
|
||||
if (gogAPI->getError())
|
||||
{
|
||||
std::cerr << gogAPI->getErrorMessage() << std::endl;
|
||||
gogAPI->clearError();
|
||||
continue;
|
||||
}
|
||||
std::cout << "Repairing file " << filepath << std::endl;
|
||||
this->repairFile(url, filepath, std::string(), games[i].gamename);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
if (response.empty())
|
||||
{
|
||||
std::cerr << "Found nothing in " << vGameFiles[i].galaxy_downlink_json_url << ", skipping file" << std::endl;
|
||||
continue;
|
||||
}
|
||||
jsonparser->parse(response, downlinkJson);
|
||||
|
||||
if (!downlinkJson.isMember("downlink"))
|
||||
{
|
||||
std::cerr << "Invalid JSON response, skipping file" << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Patches (use remote or local file)
|
||||
if (Globals::globalConfig.dlConf.bPatches)
|
||||
std::string xml_url;
|
||||
if (downlinkJson.isMember("checksum"))
|
||||
if (!downlinkJson["checksum"].empty())
|
||||
xml_url = downlinkJson["checksum"].asString();
|
||||
|
||||
// Get XML data
|
||||
std::string XML = "";
|
||||
if (conf.dlConf.bRemoteXML && !xml_url.empty())
|
||||
XML = gogGalaxy->getResponse(xml_url);
|
||||
|
||||
// Repair
|
||||
bool bUseLocalXML = !conf.dlConf.bRemoteXML;
|
||||
|
||||
// Use local XML data for extras
|
||||
if (XML.empty() && (type & GFTYPE_EXTRA))
|
||||
bUseLocalXML = true;
|
||||
|
||||
if (!XML.empty() || bUseLocalXML)
|
||||
{
|
||||
for (unsigned int j = 0; j < games[i].patches.size(); ++j)
|
||||
{
|
||||
std::string filepath = games[i].patches[j].getFilepath();
|
||||
if (Globals::globalConfig.blacklist.isBlacklisted(filepath))
|
||||
{
|
||||
if (Globals::globalConfig.bVerbose)
|
||||
std::cerr << "skipped blacklisted file " << filepath << std::endl;
|
||||
continue;
|
||||
}
|
||||
std::string url = downlinkJson["downlink"].asString();
|
||||
|
||||
// Get XML data
|
||||
std::string XML = "";
|
||||
if (Globals::globalConfig.dlConf.bRemoteXML)
|
||||
{
|
||||
XML = gogAPI->getXML(games[i].gamename, games[i].patches[j].id);
|
||||
if (gogAPI->getError())
|
||||
{
|
||||
std::cerr << gogAPI->getErrorMessage() << std::endl;
|
||||
gogAPI->clearError();
|
||||
}
|
||||
}
|
||||
|
||||
std::string url = gogAPI->getPatchLink(games[i].gamename, games[i].patches[j].id);
|
||||
if (gogAPI->getError())
|
||||
{
|
||||
std::cerr << gogAPI->getErrorMessage() << std::endl;
|
||||
gogAPI->clearError();
|
||||
continue;
|
||||
}
|
||||
std::cout << "Repairing file " << filepath << std::endl;
|
||||
this->repairFile(url, filepath, XML, games[i].gamename);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Language packs (GOG doesn't provide XML data for language packs, use local file)
|
||||
if (Globals::globalConfig.dlConf.bLanguagePacks)
|
||||
{
|
||||
for (unsigned int j = 0; j < games[i].languagepacks.size(); ++j)
|
||||
{
|
||||
std::string filepath = games[i].languagepacks[j].getFilepath();
|
||||
if (Globals::globalConfig.blacklist.isBlacklisted(filepath))
|
||||
{
|
||||
if (Globals::globalConfig.bVerbose)
|
||||
std::cerr << "skipped blacklisted file " << filepath << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string url = gogAPI->getLanguagePackLink(games[i].gamename, games[i].languagepacks[j].id);
|
||||
if (gogAPI->getError())
|
||||
{
|
||||
std::cerr << gogAPI->getErrorMessage() << std::endl;
|
||||
gogAPI->clearError();
|
||||
continue;
|
||||
}
|
||||
std::cout << "Repairing file " << filepath << std::endl;
|
||||
this->repairFile(url, filepath, std::string(), games[i].gamename);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
if (Globals::globalConfig.dlConf.bDLC && !games[i].dlcs.empty())
|
||||
{
|
||||
for (unsigned int j = 0; j < games[i].dlcs.size(); ++j)
|
||||
{
|
||||
if (Globals::globalConfig.dlConf.bInstallers)
|
||||
{
|
||||
for (unsigned int k = 0; k < games[i].dlcs[j].installers.size(); ++k)
|
||||
{
|
||||
std::string filepath = games[i].dlcs[j].installers[k].getFilepath();
|
||||
if (Globals::globalConfig.blacklist.isBlacklisted(filepath))
|
||||
{
|
||||
if (Globals::globalConfig.bVerbose)
|
||||
std::cerr << "skipped blacklisted file " << filepath << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get XML data
|
||||
std::string XML = "";
|
||||
if (Globals::globalConfig.dlConf.bRemoteXML)
|
||||
{
|
||||
XML = gogAPI->getXML(games[i].dlcs[j].gamename, games[i].dlcs[j].installers[k].id);
|
||||
if (gogAPI->getError())
|
||||
{
|
||||
std::cerr << gogAPI->getErrorMessage() << std::endl;
|
||||
gogAPI->clearError();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Repair
|
||||
bool bUseLocalXML = !Globals::globalConfig.dlConf.bRemoteXML;
|
||||
if (!XML.empty() || bUseLocalXML)
|
||||
{
|
||||
std::string url = gogAPI->getInstallerLink(games[i].dlcs[j].gamename, games[i].dlcs[j].installers[k].id);
|
||||
if (gogAPI->getError())
|
||||
{
|
||||
std::cerr << gogAPI->getErrorMessage() << std::endl;
|
||||
gogAPI->clearError();
|
||||
continue;
|
||||
}
|
||||
std::cout << "Repairing file " << filepath << std::endl;
|
||||
this->repairFile(url, filepath, XML, games[i].dlcs[j].gamename);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Globals::globalConfig.dlConf.bPatches)
|
||||
{
|
||||
for (unsigned int k = 0; k < games[i].dlcs[j].patches.size(); ++k)
|
||||
{
|
||||
std::string filepath = games[i].dlcs[j].patches[k].getFilepath();
|
||||
if (Globals::globalConfig.blacklist.isBlacklisted(filepath)) {
|
||||
if (Globals::globalConfig.bVerbose)
|
||||
std::cerr << "skipped blacklisted file " << filepath << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get XML data
|
||||
std::string XML = "";
|
||||
if (Globals::globalConfig.dlConf.bRemoteXML)
|
||||
{
|
||||
XML = gogAPI->getXML(games[i].dlcs[j].gamename, games[i].dlcs[j].patches[k].id);
|
||||
if (gogAPI->getError())
|
||||
{
|
||||
std::cerr << gogAPI->getErrorMessage() << std::endl;
|
||||
gogAPI->clearError();
|
||||
}
|
||||
}
|
||||
|
||||
std::string url = gogAPI->getPatchLink(games[i].dlcs[j].gamename, games[i].dlcs[j].patches[k].id);
|
||||
if (gogAPI->getError())
|
||||
{
|
||||
std::cerr << gogAPI->getErrorMessage() << std::endl;
|
||||
gogAPI->clearError();
|
||||
continue;
|
||||
}
|
||||
std::cout << "Repairing file " << filepath << std::endl;
|
||||
this->repairFile(url, filepath, XML, games[i].dlcs[j].gamename);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
if (Globals::globalConfig.dlConf.bExtras)
|
||||
{
|
||||
for (unsigned int k = 0; k < games[i].dlcs[j].extras.size(); ++k)
|
||||
{
|
||||
std::string filepath = games[i].dlcs[j].extras[k].getFilepath();
|
||||
if (Globals::globalConfig.blacklist.isBlacklisted(filepath)) {
|
||||
if (Globals::globalConfig.bVerbose)
|
||||
std::cerr << "skipped blacklisted file " << filepath << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string url = gogAPI->getExtraLink(games[i].dlcs[j].gamename, games[i].dlcs[j].extras[k].id);
|
||||
if (gogAPI->getError())
|
||||
{
|
||||
std::cerr << gogAPI->getErrorMessage() << std::endl;
|
||||
gogAPI->clearError();
|
||||
continue;
|
||||
}
|
||||
std::cout << "Repairing file " << filepath << std::endl;
|
||||
this->repairFile(url, filepath, std::string(), games[i].dlcs[j].gamename);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
if (Globals::globalConfig.dlConf.bLanguagePacks)
|
||||
{
|
||||
for (unsigned int k = 0; k < games[i].dlcs[j].languagepacks.size(); ++k)
|
||||
{
|
||||
std::string filepath = games[i].dlcs[j].languagepacks[k].getFilepath();
|
||||
if (Globals::globalConfig.blacklist.isBlacklisted(filepath)) {
|
||||
if (Globals::globalConfig.bVerbose)
|
||||
std::cerr << "skipped blacklisted file " << filepath << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get XML data
|
||||
std::string XML = "";
|
||||
if (Globals::globalConfig.dlConf.bRemoteXML)
|
||||
{
|
||||
XML = gogAPI->getXML(games[i].dlcs[j].gamename, games[i].dlcs[j].languagepacks[k].id);
|
||||
if (gogAPI->getError())
|
||||
{
|
||||
std::cerr << gogAPI->getErrorMessage() << std::endl;
|
||||
gogAPI->clearError();
|
||||
}
|
||||
}
|
||||
|
||||
std::string url = gogAPI->getLanguagePackLink(games[i].dlcs[j].gamename, games[i].dlcs[j].languagepacks[k].id);
|
||||
if (gogAPI->getError())
|
||||
{
|
||||
std::cerr << gogAPI->getErrorMessage() << std::endl;
|
||||
gogAPI->clearError();
|
||||
continue;
|
||||
}
|
||||
std::cout << "Repairing file " << filepath << std::endl;
|
||||
this->repairFile(url, filepath, XML, games[i].dlcs[j].gamename);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << "Repairing file " << filepath << std::endl;
|
||||
this->repairFile(url, filepath, XML, vGameFiles[i].gamename);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
delete jsonparser;
|
||||
}
|
||||
|
||||
void Downloader::download()
|
||||
@ -996,20 +807,24 @@ void Downloader::download()
|
||||
|
||||
for (unsigned int i = 0; i < games.size(); ++i)
|
||||
{
|
||||
if (Globals::globalConfig.dlConf.bSaveSerials && !games[i].serials.empty())
|
||||
gameSpecificConfig conf;
|
||||
conf.dlConf = Globals::globalConfig.dlConf;
|
||||
conf.dirConf = Globals::globalConfig.dirConf;
|
||||
|
||||
if (conf.dlConf.bSaveSerials && !games[i].serials.empty())
|
||||
{
|
||||
std::string filepath = games[i].getSerialsFilepath();
|
||||
this->saveSerials(games[i].serials, filepath);
|
||||
}
|
||||
|
||||
if (Globals::globalConfig.dlConf.bSaveChangelogs && !games[i].changelog.empty())
|
||||
if (conf.dlConf.bSaveChangelogs && !games[i].changelog.empty())
|
||||
{
|
||||
std::string filepath = games[i].getChangelogFilepath();
|
||||
this->saveChangelog(games[i].changelog, filepath);
|
||||
}
|
||||
|
||||
// Download covers
|
||||
if (Globals::globalConfig.dlConf.bCover && !Globals::globalConfig.bUpdateCheck)
|
||||
if (conf.dlConf.bCover && !Globals::globalConfig.bUpdateCheck)
|
||||
{
|
||||
if (!games[i].installers.empty())
|
||||
{
|
||||
@ -1023,71 +838,71 @@ void Downloader::download()
|
||||
}
|
||||
}
|
||||
|
||||
if (Globals::globalConfig.dlConf.bInstallers)
|
||||
if (conf.dlConf.bInstallers)
|
||||
{
|
||||
for (unsigned int j = 0; j < games[i].installers.size(); ++j)
|
||||
{
|
||||
dlQueue.push(games[i].installers[j]);
|
||||
}
|
||||
}
|
||||
if (Globals::globalConfig.dlConf.bPatches)
|
||||
if (conf.dlConf.bPatches)
|
||||
{
|
||||
for (unsigned int j = 0; j < games[i].patches.size(); ++j)
|
||||
{
|
||||
dlQueue.push(games[i].patches[j]);
|
||||
}
|
||||
}
|
||||
if (Globals::globalConfig.dlConf.bExtras)
|
||||
if (conf.dlConf.bExtras)
|
||||
{
|
||||
for (unsigned int j = 0; j < games[i].extras.size(); ++j)
|
||||
{
|
||||
dlQueue.push(games[i].extras[j]);
|
||||
}
|
||||
}
|
||||
if (Globals::globalConfig.dlConf.bLanguagePacks)
|
||||
if (conf.dlConf.bLanguagePacks)
|
||||
{
|
||||
for (unsigned int j = 0; j < games[i].languagepacks.size(); ++j)
|
||||
{
|
||||
dlQueue.push(games[i].languagepacks[j]);
|
||||
}
|
||||
}
|
||||
if (Globals::globalConfig.dlConf.bDLC && !games[i].dlcs.empty())
|
||||
if (conf.dlConf.bDLC && !games[i].dlcs.empty())
|
||||
{
|
||||
for (unsigned int j = 0; j < games[i].dlcs.size(); ++j)
|
||||
{
|
||||
if (Globals::globalConfig.dlConf.bSaveSerials && !games[i].dlcs[j].serials.empty())
|
||||
if (conf.dlConf.bSaveSerials && !games[i].dlcs[j].serials.empty())
|
||||
{
|
||||
std::string filepath = games[i].dlcs[j].getSerialsFilepath();
|
||||
this->saveSerials(games[i].dlcs[j].serials, filepath);
|
||||
}
|
||||
if (Globals::globalConfig.dlConf.bSaveChangelogs && !games[i].dlcs[j].changelog.empty())
|
||||
if (conf.dlConf.bSaveChangelogs && !games[i].dlcs[j].changelog.empty())
|
||||
{
|
||||
std::string filepath = games[i].dlcs[j].getChangelogFilepath();
|
||||
this->saveChangelog(games[i].dlcs[j].changelog, filepath);
|
||||
}
|
||||
|
||||
if (Globals::globalConfig.dlConf.bInstallers)
|
||||
if (conf.dlConf.bInstallers)
|
||||
{
|
||||
for (unsigned int k = 0; k < games[i].dlcs[j].installers.size(); ++k)
|
||||
{
|
||||
dlQueue.push(games[i].dlcs[j].installers[k]);
|
||||
}
|
||||
}
|
||||
if (Globals::globalConfig.dlConf.bPatches)
|
||||
if (conf.dlConf.bPatches)
|
||||
{
|
||||
for (unsigned int k = 0; k < games[i].dlcs[j].patches.size(); ++k)
|
||||
{
|
||||
dlQueue.push(games[i].dlcs[j].patches[k]);
|
||||
}
|
||||
}
|
||||
if (Globals::globalConfig.dlConf.bExtras)
|
||||
if (conf.dlConf.bExtras)
|
||||
{
|
||||
for (unsigned int k = 0; k < games[i].dlcs[j].extras.size(); ++k)
|
||||
{
|
||||
dlQueue.push(games[i].dlcs[j].extras[k]);
|
||||
}
|
||||
}
|
||||
if (Globals::globalConfig.dlConf.bLanguagePacks)
|
||||
if (conf.dlConf.bLanguagePacks)
|
||||
{
|
||||
for (unsigned int k = 0; k < games[i].dlcs[j].languagepacks.size(); ++k)
|
||||
{
|
||||
@ -2030,7 +1845,9 @@ std::string Downloader::getSerialsFromJSON(const Json::Value& json)
|
||||
|
||||
if (cdkey.find("<span>") == std::string::npos)
|
||||
{
|
||||
serials << cdkey << std::endl;
|
||||
boost::regex expression("<br\\h*/?>");
|
||||
std::string text = boost::regex_replace(cdkey, expression, "\n");
|
||||
serials << text << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2535,6 +2352,7 @@ std::vector<gameDetails> Downloader::getGameDetailsFromJsonNode(Json::Value root
|
||||
fileDetails.silent = fileDetailsNode["silent"].asInt();
|
||||
fileDetails.gamename = fileDetailsNode["gamename"].asString();
|
||||
fileDetails.type = fileDetailsNode["type"].asUInt();
|
||||
fileDetails.galaxy_downlink_json_url = fileDetailsNode["galaxy_downlink_json_url"].asString();
|
||||
|
||||
if (nodeName != "extras" && !(fileDetails.platform & conf.dlConf.iInstallerPlatform))
|
||||
continue;
|
||||
@ -2679,6 +2497,13 @@ void Downloader::saveChangelog(const std::string& changelog, const std::string&
|
||||
|
||||
int Downloader::downloadFileWithId(const std::string& fileid_string, const std::string& output_filepath)
|
||||
{
|
||||
if (!gogAPI->isLoggedIn())
|
||||
{
|
||||
std::cout << "API not logged in. This feature doesn't work without valid API login." << std::endl;
|
||||
std::cout << "Try to login with --login-api" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int res = 1;
|
||||
size_t pos = fileid_string.find("/");
|
||||
if (pos == std::string::npos)
|
||||
@ -2767,20 +2592,20 @@ void Downloader::processDownloadQueue(Config conf, const unsigned int& tid)
|
||||
{
|
||||
std::string msg_prefix = "[Thread #" + std::to_string(tid) + "]";
|
||||
|
||||
API* api = new API(conf.apiConf.sToken, conf.apiConf.sSecret);
|
||||
api->curlSetOpt(CURLOPT_SSL_VERIFYPEER, conf.curlConf.bVerifyPeer);
|
||||
api->curlSetOpt(CURLOPT_CONNECTTIMEOUT, conf.curlConf.iTimeout);
|
||||
if (!conf.curlConf.sCACertPath.empty())
|
||||
api->curlSetOpt(CURLOPT_CAINFO, conf.curlConf.sCACertPath.c_str());
|
||||
|
||||
if (!api->init())
|
||||
galaxyAPI* galaxy = new galaxyAPI(Globals::globalConfig.curlConf);
|
||||
if (!galaxy->init())
|
||||
{
|
||||
delete api;
|
||||
msgQueue.push(Message("API init failed", MSGTYPE_ERROR, msg_prefix));
|
||||
vDownloadInfo[tid].setStatus(DLSTATUS_FINISHED);
|
||||
return;
|
||||
if (!galaxy->refreshLogin())
|
||||
{
|
||||
delete galaxy;
|
||||
msgQueue.push(Message("Galaxy API failed to refresh login", MSGTYPE_ERROR, msg_prefix));
|
||||
vDownloadInfo[tid].setStatus(DLSTATUS_FINISHED);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Json::Reader *jsonparser = new Json::Reader;
|
||||
|
||||
CURL* dlhandle = curl_easy_init();
|
||||
curl_easy_setopt(dlhandle, CURLOPT_FOLLOWLOCATION, 1);
|
||||
curl_easy_setopt(dlhandle, CURLOPT_USERAGENT, conf.curlConf.sUserAgent.c_str());
|
||||
@ -2870,32 +2695,49 @@ void Downloader::processDownloadQueue(Config conf, const unsigned int& tid)
|
||||
bool bSameVersion = true; // assume same version
|
||||
bool bLocalXMLExists = boost::filesystem::exists(local_xml_file); // This is additional check to see if remote xml should be saved to speed up future version checks
|
||||
|
||||
// Get downlink JSON from Galaxy API
|
||||
Json::Value downlinkJson;
|
||||
std::string response = galaxy->getResponse(gf.galaxy_downlink_json_url);
|
||||
|
||||
if (response.empty())
|
||||
{
|
||||
msgQueue.push(Message("Found nothing in " + gf.galaxy_downlink_json_url + ", skipping file", MSGTYPE_WARNING, msg_prefix));
|
||||
continue;
|
||||
}
|
||||
jsonparser->parse(response, downlinkJson);
|
||||
|
||||
if (!downlinkJson.isMember("downlink"))
|
||||
{
|
||||
msgQueue.push(Message("Invalid JSON response, skipping file", MSGTYPE_WARNING, msg_prefix));
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string xml;
|
||||
if (gf.type & (GFTYPE_INSTALLER | GFTYPE_PATCH) && conf.dlConf.bRemoteXML)
|
||||
{
|
||||
xml = api->getXML(gf.gamename, gf.id);
|
||||
if (api->getError())
|
||||
std::string xml_url;
|
||||
if (downlinkJson.isMember("checksum"))
|
||||
if (!downlinkJson["checksum"].empty())
|
||||
xml_url = downlinkJson["checksum"].asString();
|
||||
|
||||
// Get XML data
|
||||
if (conf.dlConf.bRemoteXML && !xml_url.empty())
|
||||
xml = galaxy->getResponse(xml_url);
|
||||
|
||||
if (!xml.empty())
|
||||
{
|
||||
msgQueue.push(Message(api->getErrorMessage(), MSGTYPE_ERROR, msg_prefix));
|
||||
api->clearError();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!xml.empty())
|
||||
std::string localHash = Util::getLocalFileHash(conf.sXMLDirectory, filepath.string(), gf.gamename);
|
||||
// Do version check if local hash exists
|
||||
if (!localHash.empty())
|
||||
{
|
||||
std::string localHash = Util::getLocalFileHash(conf.sXMLDirectory, filepath.string(), gf.gamename);
|
||||
// Do version check if local hash exists
|
||||
if (!localHash.empty())
|
||||
tinyxml2::XMLDocument remote_xml;
|
||||
remote_xml.Parse(xml.c_str());
|
||||
tinyxml2::XMLElement *fileElem = remote_xml.FirstChildElement("file");
|
||||
if (fileElem)
|
||||
{
|
||||
tinyxml2::XMLDocument remote_xml;
|
||||
remote_xml.Parse(xml.c_str());
|
||||
tinyxml2::XMLElement *fileElem = remote_xml.FirstChildElement("file");
|
||||
if (fileElem)
|
||||
{
|
||||
std::string remoteHash = fileElem->Attribute("md5");
|
||||
if (remoteHash != localHash)
|
||||
bSameVersion = false;
|
||||
}
|
||||
std::string remoteHash = fileElem->Attribute("md5");
|
||||
if (remoteHash != localHash)
|
||||
bSameVersion = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2959,26 +2801,7 @@ void Downloader::processDownloadQueue(Config conf, const unsigned int& tid)
|
||||
}
|
||||
}
|
||||
|
||||
// Get download url
|
||||
std::string url;
|
||||
if (gf.type & GFTYPE_INSTALLER)
|
||||
url = api->getInstallerLink(gf.gamename, gf.id);
|
||||
else if (gf.type & GFTYPE_PATCH)
|
||||
url = api->getPatchLink(gf.gamename, gf.id);
|
||||
else if (gf.type & GFTYPE_LANGPACK)
|
||||
url = api->getLanguagePackLink(gf.gamename, gf.id);
|
||||
else if (gf.type & GFTYPE_EXTRA)
|
||||
url = api->getExtraLink(gf.gamename, gf.id);
|
||||
else
|
||||
url = api->getExtraLink(gf.gamename, gf.id); // assume extra if type didn't match any of the others
|
||||
|
||||
if (api->getError())
|
||||
{
|
||||
msgQueue.push(Message(api->getErrorMessage(), MSGTYPE_ERROR, msg_prefix));
|
||||
api->clearError();
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string url = downlinkJson["downlink"].asString();
|
||||
curl_easy_setopt(dlhandle, CURLOPT_URL, url.c_str());
|
||||
do
|
||||
{
|
||||
@ -3092,7 +2915,8 @@ void Downloader::processDownloadQueue(Config conf, const unsigned int& tid)
|
||||
}
|
||||
|
||||
curl_easy_cleanup(dlhandle);
|
||||
delete api;
|
||||
delete jsonparser;
|
||||
delete galaxy;
|
||||
|
||||
vDownloadInfo[tid].setStatus(DLSTATUS_FINISHED);
|
||||
msgQueue.push(Message("Finished all tasks", MSGTYPE_INFO, msg_prefix));
|
||||
@ -3302,25 +3126,23 @@ void Downloader::getGameDetailsThread(Config config, const unsigned int& tid)
|
||||
{
|
||||
std::string msg_prefix = "[Thread #" + std::to_string(tid) + "]";
|
||||
|
||||
API* api = new API(config.apiConf.sToken, config.apiConf.sSecret);
|
||||
api->curlSetOpt(CURLOPT_SSL_VERIFYPEER, config.curlConf.bVerifyPeer);
|
||||
api->curlSetOpt(CURLOPT_CONNECTTIMEOUT, config.curlConf.iTimeout);
|
||||
if (!config.curlConf.sCACertPath.empty())
|
||||
api->curlSetOpt(CURLOPT_CAINFO, config.curlConf.sCACertPath.c_str());
|
||||
|
||||
if (!api->init())
|
||||
galaxyAPI* galaxy = new galaxyAPI(Globals::globalConfig.curlConf);
|
||||
if (!galaxy->init())
|
||||
{
|
||||
delete api;
|
||||
msgQueue.push(Message("API init failed", MSGTYPE_ERROR, msg_prefix));
|
||||
vDownloadInfo[tid].setStatus(DLSTATUS_FINISHED);
|
||||
return;
|
||||
if (!galaxy->refreshLogin())
|
||||
{
|
||||
delete galaxy;
|
||||
msgQueue.push(Message("Galaxy API failed to refresh login", MSGTYPE_ERROR, msg_prefix));
|
||||
vDownloadInfo[tid].setStatus(DLSTATUS_FINISHED);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Create new GOG website handle
|
||||
Website* website = new Website();
|
||||
if (!website->IsLoggedIn())
|
||||
{
|
||||
delete api;
|
||||
delete galaxy;
|
||||
delete website;
|
||||
msgQueue.push(Message("Website not logged in", MSGTYPE_ERROR, msg_prefix));
|
||||
vDownloadInfo[tid].setStatus(DLSTATUS_FINISHED);
|
||||
@ -3335,7 +3157,6 @@ void Downloader::getGameDetailsThread(Config config, const unsigned int& tid)
|
||||
while (gameItemQueue.try_pop(game_item))
|
||||
{
|
||||
gameDetails game;
|
||||
bool bHasDLC = !game_item.dlcnames.empty();
|
||||
|
||||
gameSpecificConfig conf;
|
||||
conf.dlConf = config.dlConf;
|
||||
@ -3380,164 +3201,50 @@ void Downloader::getGameDetailsThread(Config config, const unsigned int& tid)
|
||||
}
|
||||
}
|
||||
|
||||
game = api->getGameDetails(game_item.name, conf.dlConf.iInstallerPlatform, conf.dlConf.iInstallerLanguage, conf.dlConf.bDuplicateHandler);
|
||||
game.product_id = game_item.id;
|
||||
if (!api->getError())
|
||||
Json::Value product_info = galaxy->getProductInfo(game_item.id);
|
||||
game = galaxy->productInfoJsonToGameDetails(product_info, conf.dlConf);
|
||||
game.filterWithPriorities(conf);
|
||||
|
||||
Json::Value gameDetailsJSON;
|
||||
|
||||
if (!game_item.gamedetailsjson.empty())
|
||||
gameDetailsJSON = game_item.gamedetailsjson;
|
||||
|
||||
if (conf.dlConf.bSaveSerials && game.serials.empty())
|
||||
{
|
||||
game.filterWithPriorities(conf);
|
||||
Json::Value gameDetailsJSON;
|
||||
|
||||
if (!game_item.gamedetailsjson.empty())
|
||||
gameDetailsJSON = game_item.gamedetailsjson;
|
||||
|
||||
if (game.extras.empty() && conf.dlConf.bExtras) // Try to get extras from account page if API didn't return any extras
|
||||
{
|
||||
if (gameDetailsJSON.empty())
|
||||
gameDetailsJSON = website->getGameDetailsJSON(game_item.id);
|
||||
game.extras = Downloader::getExtrasFromJSON(gameDetailsJSON, game_item.name, config);
|
||||
}
|
||||
if (conf.dlConf.bSaveSerials)
|
||||
{
|
||||
if (gameDetailsJSON.empty())
|
||||
gameDetailsJSON = website->getGameDetailsJSON(game_item.id);
|
||||
game.serials = Downloader::getSerialsFromJSON(gameDetailsJSON);
|
||||
}
|
||||
if (conf.dlConf.bSaveChangelogs)
|
||||
{
|
||||
if (gameDetailsJSON.empty())
|
||||
gameDetailsJSON = website->getGameDetailsJSON(game_item.id);
|
||||
game.changelog = Downloader::getChangelogFromJSON(gameDetailsJSON);
|
||||
}
|
||||
|
||||
// Ignore DLC count and try to get DLCs from JSON
|
||||
if (game.dlcs.empty() && !bHasDLC && conf.dlConf.bDLC && conf.dlConf.bIgnoreDLCCount)
|
||||
{
|
||||
if (gameDetailsJSON.empty())
|
||||
gameDetailsJSON = website->getGameDetailsJSON(game_item.id);
|
||||
|
||||
game_item.dlcnames = Util::getDLCNamesFromJSON(gameDetailsJSON["dlcs"]);
|
||||
bHasDLC = !game_item.dlcnames.empty();
|
||||
}
|
||||
|
||||
if (game.dlcs.empty() && bHasDLC && conf.dlConf.bDLC)
|
||||
{
|
||||
for (unsigned int j = 0; j < game_item.dlcnames.size(); ++j)
|
||||
{
|
||||
gameDetails dlc;
|
||||
dlc = api->getGameDetails(game_item.dlcnames[j], conf.dlConf.iInstallerPlatform, conf.dlConf.iInstallerLanguage, conf.dlConf.bDuplicateHandler);
|
||||
dlc.filterWithPriorities(conf);
|
||||
if (dlc.extras.empty() && conf.dlConf.bExtras) // Try to get extras from account page if API didn't return any extras
|
||||
{
|
||||
if (gameDetailsJSON.empty())
|
||||
gameDetailsJSON = website->getGameDetailsJSON(game_item.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("/" + game_item.dlcnames[j] + "/") != std::string::npos)
|
||||
{
|
||||
dlc.extras = Downloader::getExtrasFromJSON(gameDetailsJSON["dlcs"][k], game_item.dlcnames[j], config);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (conf.dlConf.bSaveSerials)
|
||||
{
|
||||
if (gameDetailsJSON.empty())
|
||||
gameDetailsJSON = website->getGameDetailsJSON(game_item.id);
|
||||
|
||||
// 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("/" + game_item.dlcnames[j] + "/") != std::string::npos)
|
||||
{
|
||||
dlc.serials = Downloader::getSerialsFromJSON(gameDetailsJSON["dlcs"][k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (conf.dlConf.bSaveChangelogs)
|
||||
{
|
||||
if (gameDetailsJSON.empty())
|
||||
gameDetailsJSON = website->getGameDetailsJSON(game_item.id);
|
||||
|
||||
// Make sure we save changelog for the right DLC
|
||||
for (unsigned int k = 0; k < gameDetailsJSON["dlcs"].size(); ++k)
|
||||
{
|
||||
std::vector<std::string> urls;
|
||||
if (gameDetailsJSON["dlcs"][k].isMember("changelog") && gameDetailsJSON["dlcs"][k].isMember("downloads"))
|
||||
{
|
||||
// Assuming that only DLC with installers can have changelog
|
||||
Util::getDownloaderUrlsFromJSON(gameDetailsJSON["dlcs"][k]["downloads"], urls);
|
||||
}
|
||||
|
||||
if (!urls.empty())
|
||||
{
|
||||
if (urls[0].find("/" + game_item.dlcnames[j] + "/") != std::string::npos)
|
||||
{
|
||||
dlc.changelog = Downloader::getChangelogFromJSON(gameDetailsJSON["dlcs"][k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add DLC type to all DLC files
|
||||
for (unsigned int a = 0; a < dlc.installers.size(); ++a)
|
||||
dlc.installers[a].type |= GFTYPE_DLC;
|
||||
for (unsigned int a = 0; a < dlc.extras.size(); ++a)
|
||||
dlc.extras[a].type |= GFTYPE_DLC;
|
||||
for (unsigned int a = 0; a < dlc.patches.size(); ++a)
|
||||
dlc.patches[a].type |= GFTYPE_DLC;
|
||||
for (unsigned int a = 0; a < dlc.languagepacks.size(); ++a)
|
||||
dlc.languagepacks[a].type |= GFTYPE_DLC;
|
||||
|
||||
game.dlcs.push_back(dlc);
|
||||
}
|
||||
}
|
||||
|
||||
game.makeFilepaths(conf.dirConf);
|
||||
|
||||
if (!config.bUpdateCheck)
|
||||
gameDetailsQueue.push(game);
|
||||
else
|
||||
{ // Update check, only add games that have updated files
|
||||
for (unsigned int j = 0; j < game.installers.size(); ++j)
|
||||
{
|
||||
if (game.installers[j].updated)
|
||||
{
|
||||
gameDetailsQueue.push(game);
|
||||
break; // add the game only once
|
||||
}
|
||||
}
|
||||
}
|
||||
if (gameDetailsJSON.empty())
|
||||
gameDetailsJSON = website->getGameDetailsJSON(game_item.id);
|
||||
game.serials = Downloader::getSerialsFromJSON(gameDetailsJSON);
|
||||
}
|
||||
else
|
||||
|
||||
if (conf.dlConf.bSaveChangelogs && game.changelog.empty())
|
||||
{
|
||||
msgQueue.push(Message(api->getErrorMessage(), MSGTYPE_ERROR, msg_prefix));
|
||||
api->clearError();
|
||||
continue;
|
||||
if (gameDetailsJSON.empty())
|
||||
gameDetailsJSON = website->getGameDetailsJSON(game_item.id);
|
||||
game.changelog = Downloader::getChangelogFromJSON(gameDetailsJSON);
|
||||
}
|
||||
|
||||
game.makeFilepaths(conf.dirConf);
|
||||
|
||||
if (!config.bUpdateCheck)
|
||||
gameDetailsQueue.push(game);
|
||||
else
|
||||
{ // Update check, only add games that have updated files
|
||||
for (unsigned int j = 0; j < game.installers.size(); ++j)
|
||||
{
|
||||
if (game.installers[j].updated)
|
||||
{
|
||||
gameDetailsQueue.push(game);
|
||||
break; // add the game only once
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vDownloadInfo[tid].setStatus(DLSTATUS_FINISHED);
|
||||
delete api;
|
||||
delete galaxy;
|
||||
delete website;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -95,7 +95,7 @@ bool galaxyAPI::refreshLogin()
|
||||
|
||||
bool galaxyAPI::isTokenExpired()
|
||||
{
|
||||
int res = false;
|
||||
bool res = false;
|
||||
|
||||
if (Globals::galaxyConf.isExpired())
|
||||
res = true;
|
||||
@ -254,3 +254,234 @@ std::vector<galaxyDepotItem> galaxyAPI::getDepotItemsVector(const std::string& h
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
Json::Value galaxyAPI::getProductInfo(const std::string& product_id)
|
||||
{
|
||||
Json::Value json;
|
||||
|
||||
std::string url = "https://api.gog.com/products/" + product_id + "?expand=downloads,expanded_dlcs,description,screenshots,videos,related_products,changelog";
|
||||
std::string response = this->getResponse(url);
|
||||
|
||||
Json::Reader *jsonparser = new Json::Reader;
|
||||
jsonparser->parse(response, json);
|
||||
delete jsonparser;
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
gameDetails galaxyAPI::productInfoJsonToGameDetails(const Json::Value& json, const DownloadConfig& dlConf)
|
||||
{
|
||||
gameDetails gamedetails;
|
||||
|
||||
gamedetails.gamename = json["slug"].asString();
|
||||
gamedetails.product_id = json["id"].asString();
|
||||
gamedetails.title = json["title"].asString();
|
||||
gamedetails.icon = "https:" + json["images"]["icon"].asString();
|
||||
|
||||
if (json.isMember("changelog"))
|
||||
gamedetails.changelog = json["changelog"].asString();
|
||||
|
||||
if (dlConf.bInstallers)
|
||||
{
|
||||
gamedetails.installers = this->installerJsonNodeToGameFileVector(gamedetails.gamename, json["downloads"]["installers"], dlConf.iInstallerPlatform, dlConf.iInstallerLanguage, dlConf.bDuplicateHandler);
|
||||
for (unsigned int i = 0; i < gamedetails.installers.size(); ++i)
|
||||
gamedetails.installers[i].type |= GFTYPE_INSTALLER;
|
||||
}
|
||||
|
||||
if (dlConf.bExtras)
|
||||
{
|
||||
gamedetails.extras = this->extraJsonNodeToGameFileVector(gamedetails.gamename, json["downloads"]["bonus_content"]);
|
||||
for (unsigned int i = 0; i < gamedetails.extras.size(); ++i)
|
||||
gamedetails.extras[i].type |= GFTYPE_EXTRA;
|
||||
}
|
||||
|
||||
if (dlConf.bPatches)
|
||||
{
|
||||
gamedetails.patches = this->patchJsonNodeToGameFileVector(gamedetails.gamename, json["downloads"]["patches"], dlConf.iInstallerPlatform, dlConf.iInstallerLanguage, dlConf.bDuplicateHandler);
|
||||
for (unsigned int i = 0; i < gamedetails.patches.size(); ++i)
|
||||
gamedetails.patches[i].type |= GFTYPE_PATCH;
|
||||
}
|
||||
|
||||
if (dlConf.bLanguagePacks)
|
||||
{
|
||||
gamedetails.languagepacks = this->languagepackJsonNodeToGameFileVector(gamedetails.gamename, json["downloads"]["language_packs"], dlConf.iInstallerPlatform, dlConf.iInstallerLanguage, dlConf.bDuplicateHandler);
|
||||
for (unsigned int i = 0; i < gamedetails.languagepacks.size(); ++i)
|
||||
gamedetails.languagepacks[i].type |= GFTYPE_LANGPACK;
|
||||
}
|
||||
|
||||
if (dlConf.bDLC)
|
||||
{
|
||||
if (json.isMember("expanded_dlcs"))
|
||||
{
|
||||
for (unsigned int i = 0; i < json["expanded_dlcs"].size(); ++i)
|
||||
{
|
||||
gameDetails dlc_gamedetails = this->productInfoJsonToGameDetails(json["expanded_dlcs"][i], dlConf);
|
||||
|
||||
// Add DLC type to all DLC files
|
||||
for (unsigned int j = 0; j < dlc_gamedetails.installers.size(); ++j)
|
||||
dlc_gamedetails.installers[j].type |= GFTYPE_DLC;
|
||||
for (unsigned int j = 0; j < dlc_gamedetails.extras.size(); ++j)
|
||||
dlc_gamedetails.extras[j].type |= GFTYPE_DLC;
|
||||
for (unsigned int j = 0; j < dlc_gamedetails.patches.size(); ++j)
|
||||
dlc_gamedetails.patches[j].type |= GFTYPE_DLC;
|
||||
for (unsigned int j = 0; j < dlc_gamedetails.languagepacks.size(); ++j)
|
||||
dlc_gamedetails.languagepacks[j].type |= GFTYPE_DLC;
|
||||
|
||||
gamedetails.dlcs.push_back(dlc_gamedetails);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return gamedetails;
|
||||
}
|
||||
|
||||
std::vector<gameFile> galaxyAPI::installerJsonNodeToGameFileVector(const std::string& gamename, const Json::Value& json, const unsigned int& platform, const unsigned int& lang, const bool& useDuplicateHandler)
|
||||
{
|
||||
std::vector<gameFile> gamefiles;
|
||||
unsigned int iInfoNodes = json.size();
|
||||
for (unsigned int i = 0; i < iInfoNodes; ++i)
|
||||
{
|
||||
Json::Value infoNode = json[i];
|
||||
unsigned int iFiles = infoNode["files"].size();
|
||||
std::string os = infoNode["os"].asString();
|
||||
std::string language = infoNode["language"].asString();
|
||||
std::string name = infoNode["name"].asString();
|
||||
|
||||
unsigned int iPlatform = GlobalConstants::PLATFORM_WINDOWS;
|
||||
if (os == "windows")
|
||||
iPlatform = GlobalConstants::PLATFORM_WINDOWS;
|
||||
else if (os == "linux")
|
||||
iPlatform = GlobalConstants::PLATFORM_LINUX;
|
||||
else if (os == "mac")
|
||||
iPlatform = GlobalConstants::PLATFORM_MAC;
|
||||
|
||||
if (!(iPlatform & platform))
|
||||
continue;
|
||||
|
||||
unsigned int iLanguage = GlobalConstants::LANGUAGE_EN;
|
||||
iLanguage = Util::getOptionValue(language, GlobalConstants::LANGUAGES);
|
||||
|
||||
if (!(iLanguage & lang))
|
||||
continue;
|
||||
|
||||
for (unsigned int j = 0; j < iFiles; ++j)
|
||||
{
|
||||
Json::Value fileNode = infoNode["files"][j];
|
||||
std::string downlink = fileNode["downlink"].asString();
|
||||
|
||||
std::string downlinkResponse = this->getResponse(downlink);
|
||||
|
||||
if (downlinkResponse.empty())
|
||||
continue;
|
||||
|
||||
Json::Value downlinkJson;
|
||||
Json::Reader *jsonparser = new Json::Reader;
|
||||
jsonparser->parse(downlinkResponse, downlinkJson);
|
||||
delete jsonparser;
|
||||
|
||||
std::string downlink_url = downlinkJson["downlink"].asString();
|
||||
std::string path;
|
||||
if (downlink_url.find("/" + gamename + "/") != std::string::npos)
|
||||
{
|
||||
path.assign(downlink_url.begin()+downlink_url.find("/" + gamename + "/"), downlink_url.begin()+downlink_url.find_first_of("?"));
|
||||
}
|
||||
else
|
||||
{
|
||||
path.assign(downlink_url.begin()+downlink_url.find_last_of("/")+1, downlink_url.begin()+downlink_url.find_first_of("?"));
|
||||
path = "/" + gamename + "/" + path;
|
||||
}
|
||||
|
||||
gameFile gf;
|
||||
gf.gamename = gamename;
|
||||
gf.id = fileNode["id"].asString();
|
||||
gf.platform = iPlatform;
|
||||
gf.language = iLanguage;
|
||||
gf.name = name;
|
||||
gf.path = path;
|
||||
gf.size = fileNode["size"].asString();
|
||||
gf.updated = 0; // assume not updated
|
||||
gf.galaxy_downlink_json_url = downlink;
|
||||
|
||||
if (useDuplicateHandler)
|
||||
{
|
||||
bool bDuplicate = false;
|
||||
for (unsigned int k = 0; k < gamefiles.size(); ++k)
|
||||
{
|
||||
if (gamefiles[k].path == gf.path)
|
||||
{
|
||||
gamefiles[k].language |= gf.language; // Add language code to installer
|
||||
bDuplicate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (bDuplicate)
|
||||
continue;
|
||||
}
|
||||
gamefiles.push_back(gf);
|
||||
}
|
||||
}
|
||||
|
||||
return gamefiles;
|
||||
}
|
||||
|
||||
std::vector<gameFile> galaxyAPI::patchJsonNodeToGameFileVector(const std::string& gamename, const Json::Value& json, const unsigned int& platform, const unsigned int& lang, const bool& useDuplicateHandler)
|
||||
{
|
||||
return this->installerJsonNodeToGameFileVector(gamename, json, platform, lang, useDuplicateHandler);
|
||||
}
|
||||
|
||||
std::vector<gameFile> galaxyAPI::languagepackJsonNodeToGameFileVector(const std::string& gamename, const Json::Value& json, const unsigned int& platform, const unsigned int& lang, const bool& useDuplicateHandler)
|
||||
{
|
||||
return this->installerJsonNodeToGameFileVector(gamename, json, platform, lang, useDuplicateHandler);
|
||||
}
|
||||
|
||||
std::vector<gameFile> galaxyAPI::extraJsonNodeToGameFileVector(const std::string& gamename, const Json::Value& json)
|
||||
{
|
||||
std::vector<gameFile> gamefiles;
|
||||
unsigned int iInfoNodes = json.size();
|
||||
for (unsigned int i = 0; i < iInfoNodes; ++i)
|
||||
{
|
||||
Json::Value infoNode = json[i];
|
||||
unsigned int iFiles = infoNode["files"].size();
|
||||
std::string name = infoNode["name"].asString();
|
||||
|
||||
for (unsigned int j = 0; j < iFiles; ++j)
|
||||
{
|
||||
Json::Value fileNode = infoNode["files"][j];
|
||||
std::string downlink = fileNode["downlink"].asString();
|
||||
|
||||
std::string downlinkResponse = this->getResponse(downlink);
|
||||
|
||||
if (downlinkResponse.empty())
|
||||
continue;
|
||||
|
||||
Json::Value downlinkJson;
|
||||
Json::Reader *jsonparser = new Json::Reader;
|
||||
jsonparser->parse(downlinkResponse, downlinkJson);
|
||||
delete jsonparser;
|
||||
|
||||
std::string downlink_url = downlinkJson["downlink"].asString();
|
||||
std::string path;
|
||||
if (downlink_url.find("/" + gamename + "/") != std::string::npos)
|
||||
path.assign(downlink_url.begin()+downlink_url.find("/" + gamename + "/"), downlink_url.begin()+downlink_url.find_first_of("?"));
|
||||
else
|
||||
{
|
||||
path.assign(downlink_url.begin()+downlink_url.find_last_of("/")+1, downlink_url.begin()+downlink_url.find_first_of("?"));
|
||||
path = "/" + gamename + "/extras/" + path;
|
||||
}
|
||||
|
||||
gameFile gf;
|
||||
gf.gamename = gamename;
|
||||
gf.type = GFTYPE_EXTRA;
|
||||
gf.id = fileNode["id"].asString();
|
||||
gf.name = name;
|
||||
gf.path = path;
|
||||
gf.size = fileNode["size"].asString();
|
||||
gf.updated = 0; // assume not updated
|
||||
gf.galaxy_downlink_json_url = downlink;
|
||||
|
||||
gamefiles.push_back(gf);
|
||||
}
|
||||
}
|
||||
|
||||
return gamefiles;
|
||||
}
|
||||
|
@ -24,6 +24,12 @@ void gameDetails::filterWithPriorities(const gameSpecificConfig& config)
|
||||
filterListWithPriorities(installers, config);
|
||||
filterListWithPriorities(patches, config);
|
||||
filterListWithPriorities(languagepacks, config);
|
||||
for (unsigned int i = 0; i < dlcs.size(); ++i)
|
||||
{
|
||||
filterListWithPriorities(dlcs[i].installers, config);
|
||||
filterListWithPriorities(dlcs[i].patches, config);
|
||||
filterListWithPriorities(dlcs[i].languagepacks, config);
|
||||
}
|
||||
}
|
||||
|
||||
void gameDetails::filterListWithPriorities(std::vector<gameFile>& list, const gameSpecificConfig& config)
|
||||
|
@ -43,6 +43,7 @@ Json::Value gameFile::getAsJson()
|
||||
json["silent"] = this->silent;
|
||||
json["gamename"] = this->gamename;
|
||||
json["type"] = this->type;
|
||||
json["galaxy_downlink_json_url"] = this->galaxy_downlink_json_url;
|
||||
|
||||
return json;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user