mirror of
https://github.com/Sude-/lgogdownloader.git
synced 2025-02-02 05:52:31 +01:00
Added DLC support
This commit is contained in:
parent
8435fb2566
commit
50cc5a2565
@ -37,6 +37,7 @@ class gameDetails {
|
|||||||
std::vector<gameFile> installers;
|
std::vector<gameFile> installers;
|
||||||
std::vector<gameFile> patches;
|
std::vector<gameFile> patches;
|
||||||
std::vector<gameFile> languagepacks;
|
std::vector<gameFile> languagepacks;
|
||||||
|
std::vector<gameDetails> dlcs;
|
||||||
std::string gamename;
|
std::string gamename;
|
||||||
std::string title;
|
std::string title;
|
||||||
std::string icon;
|
std::string icon;
|
||||||
|
@ -28,6 +28,7 @@ class Config
|
|||||||
bool bExtras;
|
bool bExtras;
|
||||||
bool bPatches;
|
bool bPatches;
|
||||||
bool bLanguagePacks;
|
bool bLanguagePacks;
|
||||||
|
bool bDLC;
|
||||||
bool bUnicode; // use Unicode in console output
|
bool bUnicode; // use Unicode in console output
|
||||||
bool bColor; // use colors
|
bool bColor; // use colors
|
||||||
bool bVerifyPeer;
|
bool bVerifyPeer;
|
||||||
|
@ -31,6 +31,13 @@ class Timer
|
|||||||
struct timeval last_update;
|
struct timeval last_update;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class gameItem {
|
||||||
|
public:
|
||||||
|
std::string name;
|
||||||
|
std::string id;
|
||||||
|
std::vector<std::string> dlcnames;
|
||||||
|
};
|
||||||
|
|
||||||
class Downloader
|
class Downloader
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -62,8 +69,8 @@ class Downloader
|
|||||||
std::string getRemoteFileHash(const std::string& gamename, const std::string& id);
|
std::string getRemoteFileHash(const std::string& gamename, const std::string& id);
|
||||||
|
|
||||||
int HTTP_Login(const std::string& email, const std::string& password);
|
int HTTP_Login(const std::string& email, const std::string& password);
|
||||||
std::vector< std::pair<std::string,std::string> > getGames();
|
std::vector<gameItem> getGames();
|
||||||
std::vector< std::pair<std::string,std::string> > getFreeGames();
|
std::vector<gameItem> getFreeGames();
|
||||||
std::vector<gameFile> getExtras(const std::string& gamename, const std::string& gameid);
|
std::vector<gameFile> getExtras(const std::string& gamename, const std::string& gameid);
|
||||||
|
|
||||||
static int progressCallback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow);
|
static int progressCallback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow);
|
||||||
@ -73,7 +80,7 @@ class Downloader
|
|||||||
|
|
||||||
|
|
||||||
API *gogAPI;
|
API *gogAPI;
|
||||||
std::vector< std::pair<std::string,std::string> > gameNamesIds;
|
std::vector<gameItem> gameItems;
|
||||||
std::vector<gameDetails> games;
|
std::vector<gameDetails> games;
|
||||||
std::string coverXML;
|
std::string coverXML;
|
||||||
|
|
||||||
|
3
main.cpp
3
main.cpp
@ -110,6 +110,7 @@ int main(int argc, char *argv[])
|
|||||||
bool bNoExtras = false;
|
bool bNoExtras = false;
|
||||||
bool bNoPatches = false;
|
bool bNoPatches = false;
|
||||||
bool bNoLanguagePacks = false;
|
bool bNoLanguagePacks = false;
|
||||||
|
bool bNoDLC = false;
|
||||||
bool bNoRemoteXML = false;
|
bool bNoRemoteXML = false;
|
||||||
bool bNoSubDirectories = false;
|
bool bNoSubDirectories = false;
|
||||||
// Commandline options (no config file)
|
// Commandline options (no config file)
|
||||||
@ -142,6 +143,7 @@ int main(int argc, char *argv[])
|
|||||||
("no-extras", bpo::value<bool>(&bNoExtras)->zero_tokens()->default_value(false), "Don't download/list/repair extras")
|
("no-extras", bpo::value<bool>(&bNoExtras)->zero_tokens()->default_value(false), "Don't download/list/repair extras")
|
||||||
("no-patches", bpo::value<bool>(&bNoPatches)->zero_tokens()->default_value(false), "Don't download/list/repair patches")
|
("no-patches", bpo::value<bool>(&bNoPatches)->zero_tokens()->default_value(false), "Don't download/list/repair patches")
|
||||||
("no-language-packs", bpo::value<bool>(&bNoLanguagePacks)->zero_tokens()->default_value(false), "Don't download/list/repair language packs")
|
("no-language-packs", bpo::value<bool>(&bNoLanguagePacks)->zero_tokens()->default_value(false), "Don't download/list/repair language packs")
|
||||||
|
("no-dlc", bpo::value<bool>(&bNoDLC)->zero_tokens()->default_value(false), "Don't download/list/repair DLCs")
|
||||||
("no-cover", bpo::value<bool>(&bNoCover)->zero_tokens()->default_value(false), "Don't download cover images")
|
("no-cover", bpo::value<bool>(&bNoCover)->zero_tokens()->default_value(false), "Don't download cover images")
|
||||||
("no-remote-xml", bpo::value<bool>(&bNoRemoteXML)->zero_tokens()->default_value(false), "Don't use remote XML for repair")
|
("no-remote-xml", bpo::value<bool>(&bNoRemoteXML)->zero_tokens()->default_value(false), "Don't use remote XML for repair")
|
||||||
("no-unicode", bpo::value<bool>(&bNoUnicode)->zero_tokens()->default_value(false), "Don't use Unicode in the progress bar")
|
("no-unicode", bpo::value<bool>(&bNoUnicode)->zero_tokens()->default_value(false), "Don't use Unicode in the progress bar")
|
||||||
@ -213,6 +215,7 @@ int main(int argc, char *argv[])
|
|||||||
config.bExtras = !bNoExtras;
|
config.bExtras = !bNoExtras;
|
||||||
config.bPatches = !bNoPatches;
|
config.bPatches = !bNoPatches;
|
||||||
config.bLanguagePacks = !bNoLanguagePacks;
|
config.bLanguagePacks = !bNoLanguagePacks;
|
||||||
|
config.bDLC = !bNoDLC;
|
||||||
config.bRemoteXML = !bNoRemoteXML;
|
config.bRemoteXML = !bNoRemoteXML;
|
||||||
config.bSubDirectories = !bNoSubDirectories;
|
config.bSubDirectories = !bNoSubDirectories;
|
||||||
}
|
}
|
||||||
|
@ -180,7 +180,7 @@ void Downloader::updateCheck()
|
|||||||
|
|
||||||
void Downloader::getGameList()
|
void Downloader::getGameList()
|
||||||
{
|
{
|
||||||
gameNamesIds = this->getGames();
|
gameItems = this->getGames();
|
||||||
|
|
||||||
// Filter the game list
|
// Filter the game list
|
||||||
if (!config.sGameRegex.empty())
|
if (!config.sGameRegex.empty())
|
||||||
@ -191,19 +191,19 @@ void Downloader::getGameList()
|
|||||||
|
|
||||||
if (config.sGameRegex == "free")
|
if (config.sGameRegex == "free")
|
||||||
{
|
{
|
||||||
gameNamesIds = this->getFreeGames();
|
gameItems = this->getFreeGames();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ // Filter the names
|
{ // Filter the names
|
||||||
std::vector<std::pair<std::string,std::string>> gameNamesIdsFiltered;
|
std::vector<gameItem> gameItemsFiltered;
|
||||||
boost::regex expression(config.sGameRegex);
|
boost::regex expression(config.sGameRegex);
|
||||||
boost::match_results<std::string::const_iterator> what;
|
boost::match_results<std::string::const_iterator> what;
|
||||||
for (unsigned int i = 0; i < gameNamesIds.size(); ++i)
|
for (unsigned int i = 0; i < gameItems.size(); ++i)
|
||||||
{
|
{
|
||||||
if (boost::regex_search(gameNamesIds[i].first, what, expression)) // Check if name matches the specified regex
|
if (boost::regex_search(gameItems[i].name, what, expression)) // Check if name matches the specified regex
|
||||||
gameNamesIdsFiltered.push_back(gameNamesIds[i]);
|
gameItemsFiltered.push_back(gameItems[i]);
|
||||||
}
|
}
|
||||||
gameNamesIds = gameNamesIdsFiltered;
|
gameItems = gameItemsFiltered;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -216,15 +216,29 @@ int Downloader::getGameDetails()
|
|||||||
{
|
{
|
||||||
gameDetails game;
|
gameDetails game;
|
||||||
int updated = 0;
|
int updated = 0;
|
||||||
for (unsigned int i = 0; i < gameNamesIds.size(); ++i)
|
for (unsigned int i = 0; i < gameItems.size(); ++i)
|
||||||
{
|
{
|
||||||
std::cout << "Getting game info " << i+1 << " / " << gameNamesIds.size() << "\r" << std::flush;
|
std::cout << "Getting game info " << i+1 << " / " << gameItems.size() << "\r" << std::flush;
|
||||||
game = gogAPI->getGameDetails(gameNamesIds[i].first, config.iInstallerType, config.iInstallerLanguage, config.bDuplicateHandler);
|
bool bHasDLC = !gameItems[i].dlcnames.empty();
|
||||||
|
game = gogAPI->getGameDetails(gameItems[i].name, config.iInstallerType, config.iInstallerLanguage, config.bDuplicateHandler);
|
||||||
if (!gogAPI->getError())
|
if (!gogAPI->getError())
|
||||||
{
|
{
|
||||||
if (game.extras.empty() && config.bExtras) // Try to get extras from account page if API didn't return any extras
|
if (game.extras.empty() && config.bExtras) // Try to get extras from account page if API didn't return any extras
|
||||||
{
|
{
|
||||||
game.extras = this->getExtras(gameNamesIds[i].first, gameNamesIds[i].second);
|
game.extras = this->getExtras(gameItems[i].name, gameItems[i].id);
|
||||||
|
}
|
||||||
|
if (game.dlcs.empty() && bHasDLC && config.bDLC)
|
||||||
|
{
|
||||||
|
for (unsigned int j = 0; j < gameItems[i].dlcnames.size(); ++j)
|
||||||
|
{
|
||||||
|
gameDetails dlc;
|
||||||
|
dlc = gogAPI->getGameDetails(gameItems[i].dlcnames[j], config.iInstallerType, config.iInstallerLanguage, config.bDuplicateHandler);
|
||||||
|
if (dlc.extras.empty() && config.bExtras) // Try to get extras from account page if API didn't return any extras
|
||||||
|
{
|
||||||
|
dlc.extras = this->getExtras(gameItems[i].dlcnames[j], gameItems[i].id);
|
||||||
|
}
|
||||||
|
game.dlcs.push_back(dlc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!config.bUpdateCheck)
|
if (!config.bUpdateCheck)
|
||||||
games.push_back(game);
|
games.push_back(game);
|
||||||
@ -340,12 +354,50 @@ void Downloader::listGames()
|
|||||||
<< std::endl;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (config.bDLC && !games[i].dlcs.empty())
|
||||||
|
{
|
||||||
|
std::cout << "DLCs: " << std::endl;
|
||||||
|
for (unsigned int j = 0; j < games[i].dlcs.size(); ++j)
|
||||||
|
{
|
||||||
|
for (unsigned int k = 0; k < games[i].dlcs[j].installers.size(); ++k)
|
||||||
|
{
|
||||||
|
std::cout << "\tgamename: " << games[i].dlcs[j].gamename << 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
|
||||||
|
<< "\tsize: " << games[i].dlcs[j].installers[k].size << std::endl
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
for (unsigned int k = 0; k < games[i].dlcs[j].patches.size(); ++k)
|
||||||
|
{
|
||||||
|
std::cout << "\tgamename: " << games[i].dlcs[j].gamename << 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
|
||||||
|
<< "\tsize: " << games[i].dlcs[j].patches[k].size << std::endl
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
for (unsigned int k = 0; k < games[i].dlcs[j].extras.size(); ++k)
|
||||||
|
{
|
||||||
|
std::cout << "\tgamename: " << games[i].dlcs[j].gamename << 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
|
||||||
|
<< "\tsize: " << games[i].dlcs[j].extras[k].size << std::endl
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ // List game names
|
{ // List game names
|
||||||
for (unsigned int i = 0; i < gameNamesIds.size(); ++i)
|
for (unsigned int i = 0; i < gameItems.size(); ++i)
|
||||||
std::cout << gameNamesIds[i].first << std::endl;
|
{
|
||||||
|
std::cout << gameItems[i].name << std::endl;
|
||||||
|
for (unsigned int j = 0; j < gameItems[i].dlcnames.size(); ++j)
|
||||||
|
std::cout << "+> " << gameItems[i].dlcnames[j] << std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -454,7 +506,84 @@ void Downloader::repair()
|
|||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (config.bDLC && !games[i].dlcs.empty())
|
||||||
|
{
|
||||||
|
for (unsigned int j = 0; j < games[i].dlcs.size(); ++j)
|
||||||
|
{
|
||||||
|
if (config.bInstallers)
|
||||||
|
{
|
||||||
|
for (unsigned int k = 0; k < games[i].dlcs[j].installers.size(); ++k)
|
||||||
|
{
|
||||||
|
std::string filepath = Util::makeFilepath(config.sDirectory, games[i].dlcs[j].installers[k].path, games[i].gamename, config.bSubDirectories ? "dlc" : "");
|
||||||
|
|
||||||
|
// Get XML data
|
||||||
|
std::string XML = "";
|
||||||
|
if (config.bRemoteXML)
|
||||||
|
{
|
||||||
|
XML = gogAPI->getXML(games[i].dlcs[j].gamename, games[i].dlcs[j].installers[k].id);
|
||||||
|
if (gogAPI->getError())
|
||||||
|
{
|
||||||
|
std::cout << gogAPI->getErrorMessage() << std::endl;
|
||||||
|
gogAPI->clearError();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Repair
|
||||||
|
bool bUseLocalXML = !config.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::cout << 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 (config.bPatches)
|
||||||
|
{
|
||||||
|
for (unsigned int k = 0; k < games[i].dlcs[j].patches.size(); ++k)
|
||||||
|
{
|
||||||
|
std::string filepath = Util::makeFilepath(config.sDirectory, games[i].dlcs[j].patches[k].path, games[i].gamename, config.bSubDirectories ? "dlc/patches" : "");
|
||||||
|
|
||||||
|
std::string url = gogAPI->getPatchLink(games[i].dlcs[j].gamename, games[i].dlcs[j].patches[k].id);
|
||||||
|
if (gogAPI->getError())
|
||||||
|
{
|
||||||
|
std::cout << 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 (config.bExtras)
|
||||||
|
{
|
||||||
|
for (unsigned int k = 0; k < games[i].dlcs[j].extras.size(); ++k)
|
||||||
|
{
|
||||||
|
std::string filepath = Util::makeFilepath(config.sDirectory, games[i].dlcs[j].extras[k].path, games[i].gamename, config.bSubDirectories ? "dlc/extras" : "");
|
||||||
|
|
||||||
|
std::string url = gogAPI->getExtraLink(games[i].dlcs[j].gamename, games[i].dlcs[j].extras[k].id);
|
||||||
|
if (gogAPI->getError())
|
||||||
|
{
|
||||||
|
std::cout << 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -569,12 +698,14 @@ void Downloader::download()
|
|||||||
// Download
|
// Download
|
||||||
if (!url.empty())
|
if (!url.empty())
|
||||||
{
|
{
|
||||||
if (!games[i].patches[j].name.empty())
|
std::string XML;
|
||||||
std::cout << "Dowloading: " << games[i].gamename << " " << games[i].patches[j].name << std::endl;
|
if (config.bRemoteXML)
|
||||||
std::cout << filepath << std::endl;
|
XML = gogAPI->getXML(games[i].dlcs[j].gamename, games[i].patches[j].id);
|
||||||
CURLcode result = downloadFile(url, filepath);
|
if (!games[i].dlcs[j].patches[j].name.empty())
|
||||||
|
std::cout << "Dowloading: " << games[i].patches[j].name << std::endl;
|
||||||
|
CURLcode result = this->downloadFile(url, filepath, XML, games[i].gamename);
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
if (result==CURLE_OK && config.sXMLFile == "automatic")
|
if (result==CURLE_OK && config.sXMLFile == "automatic" && XML.empty())
|
||||||
{
|
{
|
||||||
std::cout << "Starting automatic XML creation" << std::endl;
|
std::cout << "Starting automatic XML creation" << std::endl;
|
||||||
std::string xml_dir = config.sXMLDirectory + "/" + games[i].gamename;
|
std::string xml_dir = config.sXMLDirectory + "/" + games[i].gamename;
|
||||||
@ -618,6 +749,108 @@ void Downloader::download()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (config.bDLC && !games[i].dlcs.empty())
|
||||||
|
{
|
||||||
|
for (unsigned int j = 0; j < games[i].dlcs.size(); ++j)
|
||||||
|
{
|
||||||
|
if (config.bInstallers)
|
||||||
|
{
|
||||||
|
for (unsigned int k = 0; k < games[i].dlcs[j].installers.size(); ++k)
|
||||||
|
{
|
||||||
|
std::string filepath = Util::makeFilepath(config.sDirectory, games[i].dlcs[j].installers[k].path, games[i].gamename, config.bSubDirectories ? "dlc" : "");
|
||||||
|
|
||||||
|
// Get link
|
||||||
|
std::string url = gogAPI->getInstallerLink(games[i].dlcs[j].gamename, games[i].dlcs[j].installers[k].id);
|
||||||
|
if (gogAPI->getError())
|
||||||
|
{
|
||||||
|
std::cout << gogAPI->getErrorMessage() << std::endl;
|
||||||
|
gogAPI->clearError();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Download
|
||||||
|
if (!url.empty())
|
||||||
|
{
|
||||||
|
std::string XML;
|
||||||
|
if (config.bRemoteXML)
|
||||||
|
XML = gogAPI->getXML(games[i].dlcs[j].gamename, games[i].dlcs[j].installers[k].id);
|
||||||
|
if (!games[i].dlcs[j].installers[k].name.empty())
|
||||||
|
std::cout << "Dowloading: " << games[i].dlcs[j].installers[k].name << std::endl;
|
||||||
|
std::cout << filepath << std::endl;
|
||||||
|
this->downloadFile(url, filepath, XML, games[i].dlcs[j].gamename);
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (config.bPatches)
|
||||||
|
{
|
||||||
|
for (unsigned int k = 0; k < games[i].dlcs[j].patches.size(); ++k)
|
||||||
|
{
|
||||||
|
std::string filepath = Util::makeFilepath(config.sDirectory, games[i].dlcs[j].patches[k].path, games[i].gamename, config.bSubDirectories ? "dlc/patches" : "");
|
||||||
|
|
||||||
|
// Get link
|
||||||
|
std::string url = gogAPI->getPatchLink(games[i].dlcs[j].gamename, games[i].dlcs[j].patches[k].id);
|
||||||
|
if (gogAPI->getError())
|
||||||
|
{
|
||||||
|
std::cout << gogAPI->getErrorMessage() << std::endl;
|
||||||
|
gogAPI->clearError();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Download
|
||||||
|
if (!url.empty())
|
||||||
|
{
|
||||||
|
std::string XML;
|
||||||
|
if (config.bRemoteXML)
|
||||||
|
XML = gogAPI->getXML(games[i].dlcs[j].gamename, games[i].dlcs[j].patches[k].id);
|
||||||
|
if (!games[i].dlcs[j].patches[k].name.empty())
|
||||||
|
std::cout << "Dowloading: " << games[i].dlcs[j].patches[k].name << std::endl;
|
||||||
|
CURLcode result = this->downloadFile(url, filepath, XML, games[i].dlcs[j].gamename);
|
||||||
|
std::cout << std::endl;
|
||||||
|
if (result==CURLE_OK && config.sXMLFile == "automatic" && XML.empty())
|
||||||
|
{
|
||||||
|
std::cout << "Starting automatic XML creation" << std::endl;
|
||||||
|
std::string xml_dir = config.sXMLDirectory + "/" + games[i].dlcs[j].gamename;
|
||||||
|
Util::createXML(filepath, config.iChunkSize, xml_dir);
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (config.bExtras)
|
||||||
|
{
|
||||||
|
for (unsigned int k = 0; k < games[i].dlcs[j].extras.size(); ++k)
|
||||||
|
{
|
||||||
|
std::string filepath = Util::makeFilepath(config.sDirectory, games[i].dlcs[j].extras[k].path, games[i].gamename, config.bSubDirectories ? "dlc/extras" : "");
|
||||||
|
|
||||||
|
// Get link
|
||||||
|
std::string url = gogAPI->getExtraLink(games[i].dlcs[j].gamename, games[i].dlcs[j].extras[k].id);
|
||||||
|
if (gogAPI->getError())
|
||||||
|
{
|
||||||
|
std::cout << gogAPI->getErrorMessage() << std::endl;
|
||||||
|
gogAPI->clearError();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Download
|
||||||
|
if (!url.empty())
|
||||||
|
{
|
||||||
|
if (!games[i].dlcs[j].extras[k].name.empty())
|
||||||
|
std::cout << "Dowloading: " << games[i].dlcs[j].extras[k].name << std::endl;
|
||||||
|
CURLcode result = this->downloadFile(url, filepath);
|
||||||
|
std::cout << std::endl;
|
||||||
|
if (result==CURLE_OK && config.sXMLFile == "automatic")
|
||||||
|
{
|
||||||
|
std::cout << "Starting automatic XML creation" << std::endl;
|
||||||
|
std::string xml_dir = config.sXMLDirectory + "/" + games[i].dlcs[j].gamename;
|
||||||
|
Util::createXML(filepath, config.iChunkSize, xml_dir);
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1363,9 +1596,9 @@ int Downloader::HTTP_Login(const std::string& email, const std::string& password
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get list of games from account page
|
// Get list of games from account page
|
||||||
std::vector< std::pair<std::string,std::string> > Downloader::getGames()
|
std::vector<gameItem> Downloader::getGames()
|
||||||
{
|
{
|
||||||
std::vector< std::pair<std::string,std::string> > games;
|
std::vector<gameItem> games;
|
||||||
Json::Value root;
|
Json::Value root;
|
||||||
Json::Reader *jsonparser = new Json::Reader;
|
Json::Reader *jsonparser = new Json::Reader;
|
||||||
int i = 1;
|
int i = 1;
|
||||||
@ -1409,11 +1642,122 @@ std::vector< std::pair<std::string,std::string> > Downloader::getGames()
|
|||||||
std::string classname = it->attribute("class").second;
|
std::string classname = it->attribute("class").second;
|
||||||
if (classname=="shelf_game")
|
if (classname=="shelf_game")
|
||||||
{
|
{
|
||||||
|
gameItem game;
|
||||||
// Game name is contained in data-gameindex attribute
|
// Game name is contained in data-gameindex attribute
|
||||||
std::string game = it->attribute("data-gameindex").second;
|
game.name = it->attribute("data-gameindex").second;
|
||||||
std::string gameid = it->attribute("data-gameid").second;
|
game.id = it->attribute("data-gameid").second;
|
||||||
if (!game.empty() && !gameid.empty())
|
if (!game.name.empty() && !game.id.empty())
|
||||||
games.push_back(std::make_pair(game,gameid));
|
{
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
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://secure.gog.com/en/account/ajax?a=gamesListDetails&g=" + game.id;
|
||||||
|
std::string json = this->getResponse(gameDataUrl);
|
||||||
|
// Parse JSON
|
||||||
|
if (!jsonparser->parse(json, root))
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
std::cerr << "DEBUG INFO (Downloader::getGames)" << std::endl << json << std::endl;
|
||||||
|
#endif
|
||||||
|
std::cout << jsonparser->getFormatedErrorMessages();
|
||||||
|
delete jsonparser;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
|
std::cerr << "DEBUG INFO (Downloader::getGames)" << std::endl << root << 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://secure.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
games.push_back(game);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1422,11 +1766,11 @@ std::vector< std::pair<std::string,std::string> > Downloader::getGames()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get list of free games
|
// Get list of free games
|
||||||
std::vector< std::pair<std::string,std::string> > Downloader::getFreeGames()
|
std::vector<gameItem> Downloader::getFreeGames()
|
||||||
{
|
{
|
||||||
Json::Value root;
|
Json::Value root;
|
||||||
Json::Reader *jsonparser = new Json::Reader;
|
Json::Reader *jsonparser = new Json::Reader;
|
||||||
std::vector< std::pair<std::string,std::string> > games;
|
std::vector<gameItem> games;
|
||||||
std::string json = this->getResponse("https://secure.gog.com/games/ajax?a=search&f={\"price\":[\"free\"],\"sort\":\"title\"}&p=1&t=all");
|
std::string json = this->getResponse("https://secure.gog.com/games/ajax?a=search&f={\"price\":[\"free\"],\"sort\":\"title\"}&p=1&t=all");
|
||||||
|
|
||||||
// Parse JSON
|
// Parse JSON
|
||||||
@ -1458,11 +1802,12 @@ std::vector< std::pair<std::string,std::string> > Downloader::getFreeGames()
|
|||||||
std::string classname = it->attribute("class").second;
|
std::string classname = it->attribute("class").second;
|
||||||
if (classname=="gog-price game-owned")
|
if (classname=="gog-price game-owned")
|
||||||
{
|
{
|
||||||
|
gameItem game;
|
||||||
// Game name is contained in data-gameindex attribute
|
// Game name is contained in data-gameindex attribute
|
||||||
std::string game = it->attribute("data-gameindex").second;
|
game.name = it->attribute("data-gameindex").second;
|
||||||
std::string id = it->attribute("data-gameid").second;
|
game.id = it->attribute("data-gameid").second;
|
||||||
if (!game.empty() && !id.empty())
|
if (!game.name.empty() && !game.id.empty())
|
||||||
games.push_back(std::make_pair(game,id));
|
games.push_back(game);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1639,6 +1984,38 @@ void Downloader::checkOrphans()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!bFoundFile)
|
||||||
|
{ // Check dlcs
|
||||||
|
for (unsigned int k = 0; k < games[i].dlcs.size(); ++k)
|
||||||
|
{
|
||||||
|
for (unsigned int index = 0; index < games[i].dlcs[k].installers.size(); ++index)
|
||||||
|
{
|
||||||
|
if (games[i].dlcs[k].installers[index].path.find(filepath_vector[j].filename().string()) != std::string::npos)
|
||||||
|
{
|
||||||
|
bFoundFile = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bFoundFile) break;
|
||||||
|
for (unsigned int index = 0; index < games[i].dlcs[k].patches.size(); ++index)
|
||||||
|
{
|
||||||
|
if (games[i].dlcs[k].patches[index].path.find(filepath_vector[j].filename().string()) != std::string::npos)
|
||||||
|
{
|
||||||
|
bFoundFile = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (unsigned int index = 0; index < games[i].dlcs[k].extras.size(); ++index)
|
||||||
|
{
|
||||||
|
if (games[i].dlcs[k].extras[index].path.find(filepath_vector[j].filename().string()) != std::string::npos)
|
||||||
|
{
|
||||||
|
bFoundFile = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bFoundFile) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!bFoundFile)
|
if (!bFoundFile)
|
||||||
orphans.push_back(filepath_vector[j].string());
|
orphans.push_back(filepath_vector[j].string());
|
||||||
}
|
}
|
||||||
@ -1761,6 +2138,84 @@ void Downloader::checkStatus()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (config.bDLC)
|
||||||
|
{
|
||||||
|
for (unsigned int j = 0; j < games[i].dlcs.size(); ++j)
|
||||||
|
{
|
||||||
|
if (config.bInstallers)
|
||||||
|
{
|
||||||
|
for (unsigned int k = 0; k < games[i].dlcs[j].installers.size(); ++k)
|
||||||
|
{
|
||||||
|
boost::filesystem::path filepath = Util::makeFilepath(config.sDirectory, games[i].dlcs[j].installers[k].path, games[i].gamename, config.bSubDirectories ? "dlc" : "");
|
||||||
|
|
||||||
|
std::string remoteHash;
|
||||||
|
std::string localHash;
|
||||||
|
bool bHashOK = true; // assume hash OK
|
||||||
|
size_t filesize;
|
||||||
|
|
||||||
|
localHash = this->getLocalFileHash(filepath.string(), games[i].dlcs[j].gamename);
|
||||||
|
remoteHash = this->getRemoteFileHash(games[i].dlcs[j].gamename, games[i].dlcs[j].installers[k].id);
|
||||||
|
|
||||||
|
if (boost::filesystem::exists(filepath))
|
||||||
|
{
|
||||||
|
filesize = boost::filesystem::file_size(filepath);
|
||||||
|
|
||||||
|
if (remoteHash != localHash)
|
||||||
|
bHashOK = false;
|
||||||
|
|
||||||
|
std::cout << (bHashOK ? "OK " : "MD5 ") << games[i].gamename << " " << filepath.filename().string() << " " << filesize << " " << localHash << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cout << "ND " << games[i].gamename << " " << filepath.filename().string() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.bPatches)
|
||||||
|
{
|
||||||
|
for (unsigned int k = 0; k < games[i].dlcs[j].patches.size(); ++k)
|
||||||
|
{
|
||||||
|
boost::filesystem::path filepath = Util::makeFilepath(config.sDirectory, games[i].dlcs[j].patches[k].path, games[i].gamename, config.bSubDirectories ? "dlc/patches" : "");
|
||||||
|
|
||||||
|
std::string localHash = this->getLocalFileHash(filepath.string(), games[i].dlcs[j].gamename);
|
||||||
|
size_t filesize;
|
||||||
|
|
||||||
|
if (boost::filesystem::exists(filepath))
|
||||||
|
{
|
||||||
|
filesize = boost::filesystem::file_size(filepath);
|
||||||
|
std::cout << "OK " << games[i].gamename << " " << filepath.filename().string() << " " << filesize << " " << localHash << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cout << "ND " << games[i].gamename << " " << filepath.filename().string() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.bExtras)
|
||||||
|
{
|
||||||
|
for (unsigned int k = 0; k < games[i].dlcs[j].extras.size(); ++k)
|
||||||
|
{
|
||||||
|
boost::filesystem::path filepath = Util::makeFilepath(config.sDirectory, games[i].dlcs[j].extras[k].path, games[i].gamename, config.bSubDirectories ? "dlc/extras" : "");
|
||||||
|
|
||||||
|
std::string localHash = this->getLocalFileHash(filepath.string(), games[i].dlcs[j].gamename);
|
||||||
|
size_t filesize;
|
||||||
|
|
||||||
|
if (boost::filesystem::exists(filepath))
|
||||||
|
{
|
||||||
|
filesize = boost::filesystem::file_size(filepath);
|
||||||
|
std::cout << "OK " << games[i].gamename << " " << filepath.filename().string() << " " << filesize << " " << localHash << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cout << "ND " << games[i].gamename << " " << filepath.filename().string() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user