diff --git a/include/api.h b/include/api.h index 896e2dd..3fcbc85 100644 --- a/include/api.h +++ b/include/api.h @@ -34,6 +34,7 @@ class gameDetails { std::vector extras; std::vector installers; std::vector patches; + std::vector languagepacks; std::string gamename; std::string title; std::string icon; @@ -85,6 +86,7 @@ class API std::string getInstallerLink(const std::string& game_name, const std::string& id); std::string getExtraLink(const std::string& game_name, const std::string& id); std::string getPatchLink(const std::string& game_name, const std::string& id); + std::string getLanguagePackLink(const std::string& game_name, const std::string& id); std::string getXML(const std::string& game_name, const std::string& id); void clearError(); bool getError() { return this->error; }; diff --git a/include/config.h b/include/config.h index 1bae724..e8d41c0 100644 --- a/include/config.h +++ b/include/config.h @@ -28,6 +28,7 @@ class Config bool bNoInstallers; bool bNoExtras; bool bNoPatches; + bool bNoLanguagePacks; bool bNoUnicode; // don't use Unicode in console output bool bNoColor; // don't use colors bool bVerifyPeer; diff --git a/main.cpp b/main.cpp index ea0811d..5ce3444 100644 --- a/main.cpp +++ b/main.cpp @@ -95,6 +95,7 @@ int main(int argc, char *argv[]) ("no-installers", bpo::value(&config.bNoInstallers)->zero_tokens()->default_value(false), "Don't download/list/repair installers") ("no-extras", bpo::value(&config.bNoExtras)->zero_tokens()->default_value(false), "Don't download/list/repair extras") ("no-patches", bpo::value(&config.bNoPatches)->zero_tokens()->default_value(false), "Don't download/list/repair patches") + ("no-language-packs", bpo::value(&config.bNoLanguagePacks)->zero_tokens()->default_value(false), "Don't download/list/repair language packs") ("no-cover", bpo::value(&config.bNoCover)->zero_tokens()->default_value(false), "Don't download cover images") ("no-remote-xml", bpo::value(&config.bNoRemoteXML)->zero_tokens()->default_value(false), "Don't use remote XML for repair") ("no-unicode", bpo::value(&config.bNoUnicode)->zero_tokens()->default_value(false), "Don't use Unicode in the progress bar") diff --git a/src/api.cpp b/src/api.cpp index 0354003..97c9441 100644 --- a/src/api.cpp +++ b/src/api.cpp @@ -341,53 +341,98 @@ gameDetails API::getGameDetails(const std::string& game_name, const unsigned int { if (lang & GlobalConstants::LANGUAGES[i].languageId) { - unsigned int patch_number = 1; - unsigned int patch_number_file = 0; - std::string patchname = GlobalConstants::LANGUAGES[i].languageCode + std::to_string(patch_number) + "patch" + std::to_string(patch_number_file); - if (root["game"].isMember(patchname)) // found a patch node + // Try to find a patch + unsigned int patch_number = 0; + const unsigned int maxTries = 8; + std::vector patchnames; + while (patch_number < maxTries) { - Json::Value patchnode = root["game"][patchname]; - while (!patchnode.empty()) // patch numbers + unsigned int patch_number_file = 0; + while (patch_number_file < maxTries) { - while(!patchnode.empty()) // patch file numbers - { - if (patchnode.isArray()) - { - for ( unsigned int index = 0; index < patchnode.size(); ++index ) - { - Json::Value patch = patchnode[index]; + std::string patchname = GlobalConstants::LANGUAGES[i].languageCode + std::to_string(patch_number) + "patch" + std::to_string(patch_number_file); + if (root["game"].isMember(patchname)) + patchnames.push_back(patchname); + patch_number_file++; + } + patch_number++; + } - game.patches.push_back( - gameFile( false, /* patches don't have "updated" flag */ - patch["id"].isInt() ? std::to_string(patch["id"].asInt()) : patch["id"].asString(), - patch["name"].asString(), - patch["link"].asString(), - patch["size"].asString(), - GlobalConstants::LANGUAGES[i].languageId - ) - ); - } - } - else + if (!patchnames.empty()) // found at least one patch + { + for (unsigned int i = 0; i < patchnames.size(); ++i) + { + Json::Value patchnode = root["game"][patchnames[i]]; + if (patchnode.isArray()) + { + for ( unsigned int index = 0; index < patchnode.size(); ++index ) { + Json::Value patch = patchnode[index]; + game.patches.push_back( gameFile( false, /* patches don't have "updated" flag */ - patchnode["id"].isInt() ? std::to_string(patchnode["id"].asInt()) : patchnode["id"].asString(), - patchnode["name"].asString(), - patchnode["link"].asString(), - patchnode["size"].asString(), + patch["id"].isInt() ? std::to_string(patch["id"].asInt()) : patch["id"].asString(), + patch["name"].asString(), + patch["link"].asString(), + patch["size"].asString(), GlobalConstants::LANGUAGES[i].languageId - ) - ); + ) + ); } - patch_number_file++; - patchname = GlobalConstants::LANGUAGES[i].languageCode + std::to_string(patch_number) + "patch" + std::to_string(patch_number_file); - patchnode = root["game"][patchname]; } - patch_number++; - patch_number_file = 0; - patchname = GlobalConstants::LANGUAGES[i].languageCode + std::to_string(patch_number) + "patch" + std::to_string(patch_number_file); - patchnode = root["game"][patchname]; + else + { + game.patches.push_back( + gameFile( false, /* patches don't have "updated" flag */ + patchnode["id"].isInt() ? std::to_string(patchnode["id"].asInt()) : patchnode["id"].asString(), + patchnode["name"].asString(), + patchnode["link"].asString(), + patchnode["size"].asString(), + GlobalConstants::LANGUAGES[i].languageId + ) + ); + } + } + } + } + } + + // Language pack details + for (unsigned int i = 0; i < GlobalConstants::LANGUAGES.size(); ++i) + { + if (lang & GlobalConstants::LANGUAGES[i].languageId) + { + // Try to find a language pack + unsigned int lang_pack_number = 0; + const unsigned int maxTries = 4; + std::vector langpacknames; + while (lang_pack_number < maxTries) + { + unsigned int lang_pack_number_file = 0; + while (lang_pack_number_file < maxTries) + { + std::string langpackname = GlobalConstants::LANGUAGES[i].languageCode + std::to_string(lang_pack_number) + "langpack" + std::to_string(lang_pack_number_file); + if (root["game"].isMember(langpackname)) + langpacknames.push_back(langpackname); + lang_pack_number_file++; + } + lang_pack_number++; + } + + if (!langpacknames.empty()) // found at least one language pack + { + for (unsigned int i = 0; i < langpacknames.size(); ++i) + { + Json::Value langpack = root["game"][langpacknames[i]]; + game.languagepacks.push_back( + gameFile( false, /* language packs don't have "updated" flag */ + langpack["id"].isInt() ? std::to_string(langpack["id"].asInt()) : langpack["id"].asString(), + langpack["name"].asString(), + langpack["link"].asString(), + langpack["size"].asString(), + GlobalConstants::LANGUAGES[i].languageId + ) + ); } } } @@ -488,6 +533,11 @@ std::string API::getPatchLink(const std::string& game_name, const std::string& i return this->getInstallerLink(game_name, id); } +std::string API::getLanguagePackLink(const std::string& game_name, const std::string& id) +{ + return this->getInstallerLink(game_name, id); +} + std::string API::getXML(const std::string& game_name, const std::string& id) { std::string url, XML; diff --git a/src/downloader.cpp b/src/downloader.cpp index afb57db..31975fe 100644 --- a/src/downloader.cpp +++ b/src/downloader.cpp @@ -300,6 +300,19 @@ void Downloader::listGames() << std::endl; } } + // List language packs + if (!config.bNoLanguagePacks && !config.bUpdateCheck && !games[i].languagepacks.empty()) + { + std::cout << "language packs: " << std::endl; + for (unsigned int j = 0; j < games[i].languagepacks.size(); ++j) + { + std::cout << "\tid: " << games[i].languagepacks[j].id << std::endl + << "\tname: " << games[i].languagepacks[j].name << std::endl + << "\tpath: " << games[i].languagepacks[j].path << std::endl + << "\tsize: " << games[i].languagepacks[j].size << std::endl + << std::endl; + } + } } } else @@ -378,35 +391,39 @@ void Downloader::repair() { std::string filepath = Util::makeFilepath(config.sDirectory, games[i].patches[j].path, games[i].gamename); - // Get XML data - std::string XML = ""; - if (!config.bNoRemoteXML) + std::string url = gogAPI->getPatchLink(games[i].gamename, games[i].patches[j].id); + if (gogAPI->getError()) { - XML = gogAPI->getXML(games[i].gamename, games[i].patches[j].id); - if (gogAPI->getError()) - { - std::cout << gogAPI->getErrorMessage() << std::endl; - gogAPI->clearError(); - continue; - } - } - - // Repair - if (!XML.empty() || config.bNoRemoteXML) - { - std::string url = gogAPI->getPatchLink(games[i].gamename, games[i].patches[j].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); - std::cout << std::endl; + std::cout << gogAPI->getErrorMessage() << std::endl; + gogAPI->clearError(); + continue; } + std::cout << "Repairing file " << filepath << std::endl; + this->repairFile(url, filepath); + std::cout << std::endl; } } + + // Language packs (GOG doesn't provide XML data for language packs, use local file) + if (!config.bNoLanguagePacks) + { + for (unsigned int j = 0; j < games[i].languagepacks.size(); ++j) + { + std::string filepath = Util::makeFilepath(config.sDirectory, games[i].languagepacks[j].path, games[i].gamename); + + std::string url = gogAPI->getLanguagePackLink(games[i].gamename, games[i].languagepacks[j].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::cout << std::endl; + } + } + } } @@ -513,14 +530,48 @@ void Downloader::download() // Download if (!url.empty()) { - std::string XML; - if (!config.bNoRemoteXML) - XML = gogAPI->getXML(games[i].gamename, games[i].patches[j].id); if (!games[i].patches[j].name.empty()) std::cout << "Dowloading: " << games[i].gamename << " " << games[i].patches[j].name << std::endl; std::cout << filepath << std::endl; - this->downloadFile(url, filepath, XML); + CURLcode result = downloadFile(url, filepath); std::cout << std::endl; + if (result==CURLE_OK && config.sXMLFile == "automatic") + { + std::cout << "Starting automatic XML creation" << std::endl; + Util::createXML(filepath, config.iChunkSize, config.sXMLDirectory); + } + } + } + } + // Download language packs + if (!config.bNoLanguagePacks) + { + for (unsigned int j = 0; j < games[i].languagepacks.size(); ++j) + { + // Get link + std::string url = gogAPI->getLanguagePackLink(games[i].gamename, games[i].languagepacks[j].id); + if (gogAPI->getError()) + { + std::cout << gogAPI->getErrorMessage() << std::endl; + gogAPI->clearError(); + continue; + } + + std::string filepath = Util::makeFilepath(config.sDirectory, games[i].languagepacks[j].path, games[i].gamename); + + // Download + if (!url.empty()) + { + if (!games[i].languagepacks[j].name.empty()) + std::cout << "Dowloading: " << games[i].gamename << " " << games[i].languagepacks[j].name << std::endl; + std::cout << filepath << std::endl; + CURLcode result = downloadFile(url, filepath); + std::cout << std::endl; + if (result==CURLE_OK && config.sXMLFile == "automatic") + { + std::cout << "Starting automatic XML creation" << std::endl; + Util::createXML(filepath, config.iChunkSize, config.sXMLDirectory); + } } } }