Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 42 additions & 10 deletions include/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ struct DirectoryConfig
{
bool bSubDirectories;
std::string sDirectory;
std::string sWinePrefix;
std::string sGameSubdir;
std::string sInstallersSubdir;
std::string sExtrasSubdir;
Expand Down Expand Up @@ -102,6 +103,16 @@ class GalaxyConfig
return this->token_json;
}

std::string getUserId() {
std::unique_lock<std::mutex> lock(m);

if(this->token_json.isMember("user_id")) {
return this->token_json["user_id"].asString();
}

return {};
}

void setJSON(Json::Value json)
{
std::unique_lock<std::mutex> lock(m);
Expand Down Expand Up @@ -131,16 +142,34 @@ class GalaxyConfig
return this->filepath;
}

void resetClient() {
std::lock_guard<std::mutex> lock(m);
if(token_json.isMember("client_id")) {
token_json["client_id"] = default_client_id;
}
if(token_json.isMember("client_secret")) {
token_json["client_secret"] = default_client_secret;
}
}

std::string getClientId()
{
std::unique_lock<std::mutex> lock(m);
return this->client_id;
std::lock_guard<std::mutex> lock(m);
if(token_json.isMember("client_id")) {
return token_json["client_id"].asString();
}

return default_client_id;
}

std::string getClientSecret()
{
std::unique_lock<std::mutex> lock(m);
return this->client_secret;
std::lock_guard<std::mutex> lock(m);
if(token_json.isMember("client_secret")) {
return token_json["client_secret"].asString();
}

return default_client_secret;
}

std::string getRedirectUri()
Expand All @@ -154,8 +183,6 @@ class GalaxyConfig
GalaxyConfig(const GalaxyConfig& other)
{
std::lock_guard<std::mutex> guard(other.m);
client_id = other.client_id;
client_secret = other.client_secret;
redirect_uri = other.redirect_uri;
filepath = other.filepath;
token_json = other.token_json;
Expand All @@ -169,17 +196,16 @@ class GalaxyConfig
std::unique_lock<std::mutex> lock1(m, std::defer_lock);
std::unique_lock<std::mutex> lock2(other.m, std::defer_lock);
std::lock(lock1, lock2);
client_id = other.client_id;
client_secret = other.client_secret;
redirect_uri = other.redirect_uri;
filepath = other.filepath;
token_json = other.token_json;
return *this;
}
protected:
private:
std::string client_id = "46899977096215655";
std::string client_secret = "9d85c43b1482497dbbce61f6e4aa173a433796eeae2ca8c5f6129f2dc4de46d9";
const std::string default_client_id = "46899977096215655";
const std::string default_client_secret = "9d85c43b1482497dbbce61f6e4aa173a433796eeae2ca8c5f6129f2dc4de46d9";

std::string redirect_uri = "https://embed.gog.com/on_login_success?origin=client";
std::string filepath;
Json::Value token_json;
Expand Down Expand Up @@ -281,6 +307,12 @@ class Config
Blacklist blacklist;
Blacklist ignorelist;
Blacklist gamehasdlc;

// Cloud save options
std::vector<std::string> cloudWhiteList;
std::vector<std::string> cloudBlackList;
bool bCloudForce;

std::string sGameHasDLCList;

// Integers
Expand Down
19 changes: 19 additions & 0 deletions include/downloader.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,11 @@
#include <curl/curl.h>
#include <json/json.h>
#include <ctime>
#include <functional>
#include <fstream>
#include <deque>

class cloudSaveFile;
class Timer
{
public:
Expand Down Expand Up @@ -99,6 +101,14 @@ class Downloader
void clearUpdateNotifications();
void repair();
void download();

void downloadCloudSaves(const std::string& product_id, int build_index = -1);
void downloadCloudSavesById(const std::string& product_id, int build_index = -1);
void uploadCloudSaves(const std::string& product_id, int build_index = -1);
void uploadCloudSavesById(const std::string& product_id, int build_index = -1);
void deleteCloudSaves(const std::string& product_id, int build_index = -1);
void deleteCloudSavesById(const std::string& product_id, int build_index = -1);

void checkOrphans();
void checkStatus();
void updateCache();
Expand All @@ -113,9 +123,16 @@ class Downloader
void galaxyInstallGame(const std::string& product_id, int build_index = -1, const unsigned int& iGalaxyArch = GlobalConstants::ARCH_X64);
void galaxyInstallGameById(const std::string& product_id, int build_index = -1, const unsigned int& iGalaxyArch = GlobalConstants::ARCH_X64);
void galaxyShowBuilds(const std::string& product_id, int build_index = -1);
void galaxyShowCloudSaves(const std::string& product_id, int build_index = -1);
void galaxyShowLocalCloudSaves(const std::string& product_id, int build_index = -1);
void galaxyShowLocalCloudSavesById(const std::string& product_id, int build_index = -1);
void galaxyShowBuildsById(const std::string& product_id, int build_index = -1);
void galaxyShowCloudSavesById(const std::string& product_id, int build_index = -1);
protected:
private:
std::map<std::string, std::string> cloudSaveLocations(const std::string& product_id, int build_index);
int cloudSaveListByIdForEach(const std::string& product_id, int build_index, const std::function<void(cloudSaveFile &)> &f);

CURLcode downloadFile(const std::string& url, const std::string& filepath, const std::string& xml_data = std::string(), const std::string& gamename = std::string());
int repairFile(const std::string& url, const std::string& filepath, const std::string& xml_data = std::string(), const std::string& gamename = std::string());
int getGameDetails();
Expand All @@ -133,6 +150,8 @@ class Downloader
static std::string getChangelogFromJSON(const Json::Value& json);
void saveChangelog(const std::string& changelog, const std::string& filepath);
static void processDownloadQueue(Config conf, const unsigned int& tid);
static void processCloudSaveDownloadQueue(Config conf, const unsigned int& tid);
static void processCloudSaveUploadQueue(Config conf, const unsigned int& tid);
static int progressCallbackForThread(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow);
template <typename T> void printProgress(const ThreadSafeQueue<T>& download_queue);
static void getGameDetailsThread(Config config, const unsigned int& tid);
Expand Down
8 changes: 6 additions & 2 deletions include/galaxyapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,20 @@ class galaxyAPI
galaxyAPI(CurlConfig& conf);
virtual ~galaxyAPI();
int init();

bool isTokenExpired();
bool refreshLogin();
bool refreshLogin(const std::string &clientId, const std::string &clientSecret, const std::string &refreshToken, bool newSession);

Json::Value getProductBuilds(const std::string& product_id, const std::string& platform = "windows", const std::string& generation = "2");
Json::Value getManifestV1(const std::string& product_id, const std::string& build_id, const std::string& manifest_id = "repository", const std::string& platform = "windows");
Json::Value getManifestV1(const std::string& manifest_url);
Json::Value getManifestV2(std::string manifest_hash, const bool& is_dependency = false);
Json::Value getCloudPathAsJson(const std::string &clientId);
Json::Value getSecureLink(const std::string& product_id, const std::string& path);
Json::Value getDependencyLink(const std::string& path);
std::string getResponse(const std::string& url);
Json::Value getResponseJson(const std::string& url);
std::string getResponse(const std::string& url, const char *encoding = nullptr);
Json::Value getResponseJson(const std::string& url, const char *encoding = nullptr);
std::string hashToGalaxyPath(const std::string& hash);
std::vector<galaxyDepotItem> getDepotItemsVector(const std::string& hash, const bool& is_dependency = false);
Json::Value getProductInfo(const std::string& product_id);
Expand Down
2 changes: 2 additions & 0 deletions include/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ namespace Util
int createXML(std::string filepath, uintmax_t chunk_size, std::string xml_dir = std::string());
int getGameSpecificConfig(std::string gamename, gameSpecificConfig* conf, std::string directory = std::string());
int replaceString(std::string& str, const std::string& to_replace, const std::string& replace_with);
int replaceAllString(std::string& str, const std::string& to_replace, const std::string& replace_with);
void filepathReplaceReservedStrings(std::string& str, const std::string& gamename, const unsigned int& platformId = 0, const std::string& dlcname = "");
void setFilePermissions(const boost::filesystem::path& path, const boost::filesystem::perms& permissions);
int getTerminalWidth();
Expand All @@ -90,6 +91,7 @@ namespace Util
CURLcode CurlHandleGetResponse(CURL* curlhandle, std::string& response, int max_retries = -1);
curl_off_t CurlWriteMemoryCallback(char *ptr, curl_off_t size, curl_off_t nmemb, void *userp);
curl_off_t CurlWriteChunkMemoryCallback(void *contents, curl_off_t size, curl_off_t nmemb, void *userp);
curl_off_t CurlReadChunkMemoryCallback(void *contents, curl_off_t size, curl_off_t nmemb, ChunkMemoryStruct *userp);

template<typename ... Args> std::string formattedString(const std::string& format, Args ... args)
{
Expand Down
91 changes: 82 additions & 9 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,18 @@ template<typename T> void set_vm_value(std::map<std::string, bpo::variable_value
vm[option].value() = boost::any(value);
}

void ensure_trailing_slash(std::string &path, const char *default_ = nullptr) {
if (!path.empty())
{
if (path.at(path.length()-1)!='/')
path += "/";
}
else
{
path = default_; // Directory wasn't specified, use current directory
}
}

int main(int argc, char *argv[])
{
struct sigaction act;
Expand Down Expand Up @@ -151,6 +163,11 @@ int main(int argc, char *argv[])

std::string galaxy_product_id_install;
std::string galaxy_product_id_show_builds;
std::string galaxy_product_id_show_cloud_paths;
std::string galaxy_product_id_show_local_cloud_paths;
std::string galaxy_product_cloud_saves;
std::string galaxy_product_cloud_saves_delete;
std::string galaxy_upload_product_cloud_saves;
std::string tags;

std::vector<std::string> vFileIdStrings;
Expand Down Expand Up @@ -213,6 +230,11 @@ int main(int argc, char *argv[])
("cacert", bpo::value<std::string>(&Globals::globalConfig.curlConf.sCACertPath)->default_value(""), "Path to CA certificate bundle in PEM format")
("respect-umask", bpo::value<bool>(&Globals::globalConfig.bRespectUmask)->zero_tokens()->default_value(false), "Do not adjust permissions of sensitive files")
("user-agent", bpo::value<std::string>(&Globals::globalConfig.curlConf.sUserAgent)->default_value(DEFAULT_USER_AGENT), "Set user agent")

("wine-prefix", bpo::value<std::string>(&Globals::globalConfig.dirConf.sWinePrefix)->default_value("."), "Set wineprefix directory")
("cloud-whitelist", bpo::value<std::vector<std::string>>(&Globals::globalConfig.cloudWhiteList)->multitoken(), "Include this list of cloud saves, by default all cloud saves are included\n Example: --cloud-whitelist saves/AutoSave-0 saves/AutoSave-1/screenshot.png")
("cloud-blacklist", bpo::value<std::vector<std::string>>(&Globals::globalConfig.cloudBlackList)->multitoken(), "Exclude this list of cloud saves\n Example: --cloud-blacklist saves/AutoSave-0 saves/AutoSave-1/screenshot.png")
("cloud-force", bpo::value<bool>(&Globals::globalConfig.bCloudForce)->zero_tokens()->default_value(false), "Download or Upload cloud saves even if they're up-to-date\nDelete remote cloud saves even if no saves are whitelisted")
#ifdef USE_QT_GUI_LOGIN
("enable-login-gui", bpo::value<bool>(&Globals::globalConfig.bEnableLoginGUI)->zero_tokens()->default_value(false), "Enable login GUI when encountering reCAPTCHA on login form")
#endif
Expand Down Expand Up @@ -271,6 +293,11 @@ int main(int argc, char *argv[])
options_cli_experimental.add_options()
("galaxy-install", bpo::value<std::string>(&galaxy_product_id_install)->default_value(""), "Install game using product id [product_id/build_index] or gamename regex [gamename/build_id]\nBuild index is used to select a build and defaults to 0 if not specified.\n\nExample: 12345/2 selects build 2 for product 12345")
("galaxy-show-builds", bpo::value<std::string>(&galaxy_product_id_show_builds)->default_value(""), "Show game builds using product id [product_id/build_index] or gamename regex [gamename/build_id]\nBuild index is used to select a build and defaults to 0 if not specified.\n\nExample: 12345/2 selects build 2 for product 12345")
("galaxy-download-cloud-saves", bpo::value<std::string>(&galaxy_product_cloud_saves)->default_value(""), "Download cloud saves using product-id [product_id/build_index] or gamename regex [gamename/build_id]\nBuild index is used to select a build and defaults to 0 if not specified.\n\nExample: 12345/2 selects build 2 for product 12345")
("galaxy-upload-cloud-saves", bpo::value<std::string>(&galaxy_upload_product_cloud_saves)->default_value(""), "Upload cloud saves using product-id [product_id/build_index] or gamename regex [gamename/build_id]\nBuild index is used to select a build and defaults to 0 if not specified.\n\nExample: 12345/2 selects build 2 for product 12345")
("galaxy-show-cloud-saves", bpo::value<std::string>(&galaxy_product_id_show_cloud_paths)->default_value(""), "Show game cloud-saves using product id [product_id/build_index] or gamename regex [gamename/build_id]\nBuild index is used to select a build and defaults to 0 if not specified.\n\nExample: 12345/2 selects build 2 for product 12345")
("galaxy-show-local-cloud-saves", bpo::value<std::string>(&galaxy_product_id_show_local_cloud_paths)->default_value(""), "Show local cloud-saves using product id [product_id/build_index] or gamename regex [gamename/build_id]\nBuild index is used to select a build and defaults to 0 if not specified.\n\nExample: 12345/2 selects build 2 for product 12345")
("galaxy-delete-cloud-saves", bpo::value<std::string>(&galaxy_product_cloud_saves_delete)->default_value(""), "Delete cloud-saves using product id [product_id/build_index] or gamename regex [gamename/build_id]\nBuild index is used to select a build and defaults to 0 if not specified.\n\nExample: 12345/2 selects build 2 for product 12345")
("galaxy-platform", bpo::value<std::string>(&sGalaxyPlatform)->default_value("w"), galaxy_platform_text.c_str())
("galaxy-language", bpo::value<std::string>(&sGalaxyLanguage)->default_value("en"), galaxy_language_text.c_str())
("galaxy-arch", bpo::value<std::string>(&sGalaxyArch)->default_value("x64"), galaxy_arch_text.c_str())
Expand Down Expand Up @@ -578,15 +605,8 @@ int main(int argc, char *argv[])
}

// Make sure that directory has trailing slash
if (!Globals::globalConfig.dirConf.sDirectory.empty())
{
if (Globals::globalConfig.dirConf.sDirectory.at(Globals::globalConfig.dirConf.sDirectory.length()-1)!='/')
Globals::globalConfig.dirConf.sDirectory += "/";
}
else
{
Globals::globalConfig.dirConf.sDirectory = "./"; // Directory wasn't specified, use current directory
}
ensure_trailing_slash(Globals::globalConfig.dirConf.sDirectory, "./");
ensure_trailing_slash(Globals::globalConfig.dirConf.sWinePrefix, "./");

// CA certificate bundle
if (Globals::globalConfig.curlConf.sCACertPath.empty())
Expand Down Expand Up @@ -777,6 +797,39 @@ int main(int argc, char *argv[])
}
downloader.galaxyShowBuilds(product_id, build_index);
}
else if (!galaxy_product_id_show_cloud_paths.empty())
{
int build_index = -1;
std::vector<std::string> tokens = Util::tokenize(galaxy_product_id_show_cloud_paths, "/");
std::string product_id = tokens[0];
if (tokens.size() == 2)
{
build_index = std::stoi(tokens[1]);
}
downloader.galaxyShowCloudSaves(product_id, build_index);
}
else if (!galaxy_product_id_show_local_cloud_paths.empty())
{
int build_index = -1;
std::vector<std::string> tokens = Util::tokenize(galaxy_product_id_show_local_cloud_paths, "/");
std::string product_id = tokens[0];
if (tokens.size() == 2)
{
build_index = std::stoi(tokens[1]);
}
downloader.galaxyShowLocalCloudSaves(product_id, build_index);
}
else if (!galaxy_product_cloud_saves_delete.empty())
{
int build_index = -1;
std::vector<std::string> tokens = Util::tokenize(galaxy_product_cloud_saves_delete, "/");
std::string product_id = tokens[0];
if (tokens.size() == 2)
{
build_index = std::stoi(tokens[1]);
}
downloader.deleteCloudSaves(product_id, build_index);
}
else if (!galaxy_product_id_install.empty())
{
int build_index = -1;
Expand All @@ -788,6 +841,26 @@ int main(int argc, char *argv[])
}
downloader.galaxyInstallGame(product_id, build_index, Globals::globalConfig.dlConf.iGalaxyArch);
}
else if (!galaxy_product_cloud_saves.empty()) {
int build_index = -1;
std::vector<std::string> tokens = Util::tokenize(galaxy_product_cloud_saves, "/");
std::string product_id = tokens[0];
if (tokens.size() == 2)
{
build_index = std::stoi(tokens[1]);
}
downloader.downloadCloudSaves(product_id, build_index);
}
else if (!galaxy_upload_product_cloud_saves.empty()) {
int build_index = -1;
std::vector<std::string> tokens = Util::tokenize(galaxy_upload_product_cloud_saves, "/");
std::string product_id = tokens[0];
if (tokens.size() == 2)
{
build_index = std::stoi(tokens[1]);
}
downloader.uploadCloudSaves(product_id, build_index);
}
else
{
if (!Globals::globalConfig.bLogin)
Expand Down
Loading