mirror of
https://github.com/Sude-/lgogdownloader.git
synced 2024-11-20 11:49:17 +01:00
Some initial Galaxy code
Add some code for initial Galaxy support. Rewrite and move code around in preparation for GOG Galaxy API support.
This commit is contained in:
parent
22f47de4fc
commit
f2e8dde934
@ -2,7 +2,6 @@ cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR)
|
|||||||
project (lgogdownloader LANGUAGES C CXX VERSION 3.1)
|
project (lgogdownloader LANGUAGES C CXX VERSION 3.1)
|
||||||
|
|
||||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/")
|
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/")
|
||||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG=1")
|
|
||||||
set(LINK_LIBCRYPTO 0)
|
set(LINK_LIBCRYPTO 0)
|
||||||
|
|
||||||
find_program(READELF readelf DOC "Location of the readelf program")
|
find_program(READELF readelf DOC "Location of the readelf program")
|
||||||
@ -14,6 +13,7 @@ find_package(Boost
|
|||||||
regex
|
regex
|
||||||
program_options
|
program_options
|
||||||
date_time
|
date_time
|
||||||
|
iostreams
|
||||||
)
|
)
|
||||||
find_package(CURL 7.32.0 REQUIRED)
|
find_package(CURL 7.32.0 REQUIRED)
|
||||||
if(CURL_FOUND)
|
if(CURL_FOUND)
|
||||||
@ -46,6 +46,7 @@ file(GLOB SRC_FILES
|
|||||||
src/blacklist.cpp
|
src/blacklist.cpp
|
||||||
src/gamefile.cpp
|
src/gamefile.cpp
|
||||||
src/gamedetails.cpp
|
src/gamedetails.cpp
|
||||||
|
src/galaxyapi.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(GIT_CHECKOUT FALSE)
|
set(GIT_CHECKOUT FALSE)
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include "globalconstants.h"
|
#include "globalconstants.h"
|
||||||
#include "gamedetails.h"
|
#include "gamedetails.h"
|
||||||
|
#include "globals.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
289
include/config.h
289
include/config.h
@ -9,93 +9,262 @@
|
|||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
|
#include <json/json.h>
|
||||||
|
#include <mutex>
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
#include "blacklist.h"
|
#include "blacklist.h"
|
||||||
|
|
||||||
|
struct DirectoryConfig
|
||||||
|
{
|
||||||
|
bool bSubDirectories;
|
||||||
|
std::string sDirectory;
|
||||||
|
std::string sGameSubdir;
|
||||||
|
std::string sInstallersSubdir;
|
||||||
|
std::string sExtrasSubdir;
|
||||||
|
std::string sPatchesSubdir;
|
||||||
|
std::string sLanguagePackSubdir;
|
||||||
|
std::string sDLCSubdir;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DownloadConfig
|
||||||
|
{
|
||||||
|
unsigned int iInstallerPlatform;
|
||||||
|
unsigned int iInstallerLanguage;
|
||||||
|
std::vector<unsigned int> vPlatformPriority;
|
||||||
|
std::vector<unsigned int> vLanguagePriority;
|
||||||
|
unsigned int iInclude;
|
||||||
|
|
||||||
|
bool bRemoteXML;
|
||||||
|
bool bCover;
|
||||||
|
bool bSaveChangelogs;
|
||||||
|
bool bSaveSerials;
|
||||||
|
bool bAutomaticXMLCreation;
|
||||||
|
|
||||||
|
bool bInstallers;
|
||||||
|
bool bExtras;
|
||||||
|
bool bPatches;
|
||||||
|
bool bLanguagePacks;
|
||||||
|
bool bDLC;
|
||||||
|
|
||||||
|
bool bIgnoreDLCCount;
|
||||||
|
bool bDuplicateHandler;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct gameSpecificConfig
|
||||||
|
{
|
||||||
|
DownloadConfig dlConf;
|
||||||
|
DirectoryConfig dirConf;
|
||||||
|
};
|
||||||
|
|
||||||
|
class GalaxyConfig
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool isExpired()
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(m);
|
||||||
|
bool bExpired = false;
|
||||||
|
if (this->token_json.isMember("expires_at"))
|
||||||
|
bExpired = (time(NULL) > this->token_json["expires_at"].asUInt());
|
||||||
|
return bExpired;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getAccessToken()
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(m);
|
||||||
|
return this->token_json["access_token"].asString();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getRefreshToken()
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(m);
|
||||||
|
return this->token_json["refresh_token"].asString();
|
||||||
|
}
|
||||||
|
|
||||||
|
Json::Value getJSON()
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(m);
|
||||||
|
return this->token_json;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setJSON(Json::Value json)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(m);
|
||||||
|
if (!json.isMember("expires_at"))
|
||||||
|
json["expires_at"] = json["expires_in"].asUInt() + time(NULL);
|
||||||
|
this->token_json = json;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setFilepath(const std::string& path)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(m);
|
||||||
|
this->filepath = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getFilepath()
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(m);
|
||||||
|
return this->filepath;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getClientId()
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(m);
|
||||||
|
return this->client_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getClientSecret()
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(m);
|
||||||
|
return this->client_secret;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getRedirectUri()
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(m);
|
||||||
|
return this->redirect_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
GalaxyConfig() = default;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
GalaxyConfig& operator= (GalaxyConfig& other)
|
||||||
|
{
|
||||||
|
if(&other == this)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
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";
|
||||||
|
std::string redirect_uri = "https://embed.gog.com/on_login_success?origin=client";
|
||||||
|
std::string filepath;
|
||||||
|
Json::Value token_json;
|
||||||
|
mutable std::mutex m;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CurlConfig
|
||||||
|
{
|
||||||
|
bool bVerifyPeer;
|
||||||
|
bool bVerbose;
|
||||||
|
std::string sCACertPath;
|
||||||
|
std::string sCookiePath;
|
||||||
|
long int iTimeout;
|
||||||
|
curl_off_t iDownloadRate;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GogAPIConfig
|
||||||
|
{
|
||||||
|
std::string sToken;
|
||||||
|
std::string sSecret;
|
||||||
|
};
|
||||||
|
|
||||||
class Config
|
class Config
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Config() {};
|
Config() {};
|
||||||
virtual ~Config() {};
|
virtual ~Config() {};
|
||||||
bool bVerbose;
|
|
||||||
bool bRemoteXML;
|
// Booleans
|
||||||
bool bCover;
|
|
||||||
bool bUpdateCheck;
|
|
||||||
bool bDownload;
|
|
||||||
bool bList;
|
|
||||||
bool bListDetails;
|
|
||||||
bool bLoginHTTP;
|
bool bLoginHTTP;
|
||||||
bool bLoginAPI;
|
bool bLoginAPI;
|
||||||
bool bRepair;
|
|
||||||
bool bInstallers;
|
|
||||||
bool bExtras;
|
|
||||||
bool bPatches;
|
|
||||||
bool bLanguagePacks;
|
|
||||||
bool bDLC;
|
|
||||||
bool bUnicode; // use Unicode in console output
|
|
||||||
bool bColor; // use colors
|
|
||||||
bool bVerifyPeer;
|
|
||||||
bool bCheckStatus;
|
|
||||||
bool bDuplicateHandler;
|
|
||||||
bool bSaveConfig;
|
bool bSaveConfig;
|
||||||
bool bResetConfig;
|
bool bResetConfig;
|
||||||
|
|
||||||
|
bool bDownload;
|
||||||
|
bool bRepair;
|
||||||
|
bool bUpdateCheck;
|
||||||
|
bool bList;
|
||||||
|
bool bListDetails;
|
||||||
|
bool bCheckStatus;
|
||||||
|
bool bShowWishlist;
|
||||||
|
|
||||||
|
bool bVerbose;
|
||||||
|
bool bUnicode; // use Unicode in console output
|
||||||
|
bool bColor; // use colors
|
||||||
bool bReport;
|
bool bReport;
|
||||||
bool bSubDirectories;
|
bool bRespectUmask;
|
||||||
|
bool bPlatformDetection;
|
||||||
|
|
||||||
|
// Cache
|
||||||
bool bUseCache;
|
bool bUseCache;
|
||||||
bool bUpdateCache;
|
bool bUpdateCache;
|
||||||
bool bSaveSerials;
|
int iCacheValid;
|
||||||
bool bPlatformDetection;
|
|
||||||
bool bShowWishlist;
|
// Download with file id options
|
||||||
bool bAutomaticXMLCreation;
|
std::string sFileIdString;
|
||||||
bool bSaveChangelogs;
|
std::string sOutputFilename;
|
||||||
bool bRespectUmask;
|
|
||||||
std::string sGameRegex;
|
// Curl
|
||||||
std::string sDirectory;
|
CurlConfig curlConf;
|
||||||
|
|
||||||
|
// Download
|
||||||
|
DownloadConfig dlConf;
|
||||||
|
|
||||||
|
// Galaxy
|
||||||
|
//GalaxyConfig galaxyConf;
|
||||||
|
|
||||||
|
// Directories
|
||||||
|
DirectoryConfig dirConf;
|
||||||
std::string sCacheDirectory;
|
std::string sCacheDirectory;
|
||||||
std::string sXMLFile;
|
|
||||||
std::string sXMLDirectory;
|
std::string sXMLDirectory;
|
||||||
std::string sToken;
|
|
||||||
std::string sSecret;
|
|
||||||
std::string sVersionString;
|
|
||||||
std::string sVersionNumber;
|
|
||||||
std::string sConfigDirectory;
|
std::string sConfigDirectory;
|
||||||
std::string sCookiePath;
|
|
||||||
|
// File paths
|
||||||
std::string sConfigFilePath;
|
std::string sConfigFilePath;
|
||||||
std::string sBlacklistFilePath;
|
std::string sBlacklistFilePath;
|
||||||
std::string sIgnorelistFilePath;
|
std::string sIgnorelistFilePath;
|
||||||
std::string sGameHasDLCListFilePath;
|
std::string sGameHasDLCListFilePath;
|
||||||
std::string sOrphanRegex;
|
|
||||||
std::string sCoverList;
|
|
||||||
std::string sGameHasDLCList;
|
|
||||||
std::string sReportFilePath;
|
std::string sReportFilePath;
|
||||||
std::string sInstallersSubdir;
|
|
||||||
std::string sExtrasSubdir;
|
|
||||||
std::string sPatchesSubdir;
|
|
||||||
std::string sLanguagePackSubdir;
|
|
||||||
std::string sDLCSubdir;
|
|
||||||
std::string sGameSubdir;
|
|
||||||
std::string sFileIdString;
|
|
||||||
std::string sOutputFilename;
|
|
||||||
std::string sLanguagePriority;
|
|
||||||
std::string sPlatformPriority;
|
|
||||||
std::string sIgnoreDLCCountRegex;
|
|
||||||
std::string sCACertPath;
|
|
||||||
std::vector<unsigned int> vLanguagePriority;
|
|
||||||
std::vector<unsigned int> vPlatformPriority;
|
|
||||||
|
|
||||||
unsigned int iInstallerPlatform;
|
std::string sXMLFile;
|
||||||
unsigned int iInstallerLanguage;
|
|
||||||
unsigned int iInclude;
|
// Regex
|
||||||
unsigned int iThreads;
|
std::string sGameRegex;
|
||||||
int iRetries;
|
std::string sOrphanRegex;
|
||||||
int iWait;
|
std::string sIgnoreDLCCountRegex;
|
||||||
int iCacheValid;
|
|
||||||
size_t iChunkSize;
|
// Priorities
|
||||||
curl_off_t iDownloadRate;
|
std::string sPlatformPriority;
|
||||||
long int iTimeout;
|
std::string sLanguagePriority;
|
||||||
|
|
||||||
|
// General strings
|
||||||
|
std::string sVersionString;
|
||||||
|
std::string sVersionNumber;
|
||||||
|
|
||||||
|
GogAPIConfig apiConf;
|
||||||
|
|
||||||
|
// Lists
|
||||||
Blacklist blacklist;
|
Blacklist blacklist;
|
||||||
Blacklist ignorelist;
|
Blacklist ignorelist;
|
||||||
Blacklist gamehasdlc;
|
Blacklist gamehasdlc;
|
||||||
|
std::string sCoverList;
|
||||||
|
std::string sGameHasDLCList;
|
||||||
|
|
||||||
|
// Integers
|
||||||
|
int iRetries;
|
||||||
|
unsigned int iThreads;
|
||||||
|
int iWait;
|
||||||
|
size_t iChunkSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CONFIG_H__
|
#endif // CONFIG_H__
|
||||||
|
@ -26,6 +26,9 @@
|
|||||||
#include "progressbar.h"
|
#include "progressbar.h"
|
||||||
#include "website.h"
|
#include "website.h"
|
||||||
#include "threadsafequeue.h"
|
#include "threadsafequeue.h"
|
||||||
|
#include "galaxyapi.h"
|
||||||
|
#include "globals.h"
|
||||||
|
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
@ -58,10 +61,16 @@ struct xferInfo
|
|||||||
curl_off_t offset;
|
curl_off_t offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ChunkMemoryStruct
|
||||||
|
{
|
||||||
|
char *memory;
|
||||||
|
curl_off_t size;
|
||||||
|
};
|
||||||
|
|
||||||
class Downloader
|
class Downloader
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Downloader(Config &conf);
|
Downloader();
|
||||||
virtual ~Downloader();
|
virtual ~Downloader();
|
||||||
bool isLoggedIn();
|
bool isLoggedIn();
|
||||||
int init();
|
int init();
|
||||||
@ -77,9 +86,12 @@ class Downloader
|
|||||||
void showWishlist();
|
void showWishlist();
|
||||||
CURL* curlhandle;
|
CURL* curlhandle;
|
||||||
Timer timer;
|
Timer timer;
|
||||||
Config config;
|
|
||||||
ProgressBar* progressbar;
|
ProgressBar* progressbar;
|
||||||
std::deque< std::pair<time_t, uintmax_t> > TimeAndSize;
|
std::deque< std::pair<time_t, uintmax_t> > TimeAndSize;
|
||||||
|
void saveGalaxyJSON();
|
||||||
|
|
||||||
|
void galaxyInstallGame(const std::string& product_id, int build_index = -1);
|
||||||
|
void galaxyShowBuilds(const std::string& product_id, int build_index = -1);
|
||||||
protected:
|
protected:
|
||||||
private:
|
private:
|
||||||
CURLcode downloadFile(const std::string& url, const std::string& filepath, const std::string& xml_data = std::string(), const std::string& gamename = std::string());
|
CURLcode downloadFile(const std::string& url, const std::string& filepath, const std::string& xml_data = std::string(), const std::string& gamename = std::string());
|
||||||
@ -112,6 +124,7 @@ class Downloader
|
|||||||
|
|
||||||
Website *gogWebsite;
|
Website *gogWebsite;
|
||||||
API *gogAPI;
|
API *gogAPI;
|
||||||
|
galaxyAPI *gogGalaxy;
|
||||||
std::vector<gameItem> gameItems;
|
std::vector<gameItem> gameItems;
|
||||||
std::vector<gameDetails> games;
|
std::vector<gameDetails> games;
|
||||||
std::string coverXML;
|
std::string coverXML;
|
||||||
|
61
include/galaxyapi.h
Normal file
61
include/galaxyapi.h
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
/* This program is free software. It comes without any warranty, to
|
||||||
|
* the extent permitted by applicable law. You can redistribute it
|
||||||
|
* and/or modify it under the terms of the Do What The Fuck You Want
|
||||||
|
* To Public License, Version 2, as published by Sam Hocevar. See
|
||||||
|
* http://www.wtfpl.net/ for more details. */
|
||||||
|
|
||||||
|
#ifndef GALAXYAPI_H
|
||||||
|
#define GALAXYAPI_H
|
||||||
|
|
||||||
|
#include "globalconstants.h"
|
||||||
|
#include "globals.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <cstring>
|
||||||
|
#include <curl/curl.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
struct galaxyDepotItemChunk
|
||||||
|
{
|
||||||
|
std::string md5_compressed;
|
||||||
|
std::string md5_uncompressed;
|
||||||
|
off_t size_compressed;
|
||||||
|
off_t size_uncompressed;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct galaxyDepotItem
|
||||||
|
{
|
||||||
|
std::string path;
|
||||||
|
std::vector<galaxyDepotItemChunk> chunks;
|
||||||
|
off_t totalSizeCompressed;
|
||||||
|
off_t totalSizeUncompressed;
|
||||||
|
std::string md5;
|
||||||
|
};
|
||||||
|
|
||||||
|
class galaxyAPI
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
galaxyAPI(CurlConfig& conf);
|
||||||
|
virtual ~galaxyAPI();
|
||||||
|
int init();
|
||||||
|
bool isTokenExpired();
|
||||||
|
bool refreshLogin();
|
||||||
|
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 getManifestV2(std::string manifest_hash);
|
||||||
|
Json::Value getSecureLink(const std::string& product_id, const std::string& path);
|
||||||
|
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);
|
||||||
|
protected:
|
||||||
|
private:
|
||||||
|
CurlConfig curlConf;
|
||||||
|
static size_t writeMemoryCallback(char *ptr, size_t size, size_t nmemb, void *userp);
|
||||||
|
CURL* curlhandle;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // GALAXYAPI_H
|
@ -8,6 +8,7 @@
|
|||||||
#define GAMEDETAILS_H
|
#define GAMEDETAILS_H
|
||||||
|
|
||||||
#include "globalconstants.h"
|
#include "globalconstants.h"
|
||||||
|
#include "globals.h"
|
||||||
#include "gamefile.h"
|
#include "gamefile.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
@ -26,12 +27,13 @@ class gameDetails
|
|||||||
std::vector<gameFile> languagepacks;
|
std::vector<gameFile> languagepacks;
|
||||||
std::vector<gameDetails> dlcs;
|
std::vector<gameDetails> dlcs;
|
||||||
std::string gamename;
|
std::string gamename;
|
||||||
|
std::string product_id;
|
||||||
std::string title;
|
std::string title;
|
||||||
std::string icon;
|
std::string icon;
|
||||||
std::string serials;
|
std::string serials;
|
||||||
std::string changelog;
|
std::string changelog;
|
||||||
void filterWithPriorities(const gameSpecificConfig& config);
|
void filterWithPriorities(const gameSpecificConfig& config);
|
||||||
void makeFilepaths(const gameSpecificDirectoryConfig& config);
|
void makeFilepaths(const DirectoryConfig& config);
|
||||||
std::string getSerialsFilepath();
|
std::string getSerialsFilepath();
|
||||||
std::string getChangelogFilepath();
|
std::string getChangelogFilepath();
|
||||||
Json::Value getDetailsAsJson();
|
Json::Value getDetailsAsJson();
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#define GAMEFILE_H
|
#define GAMEFILE_H
|
||||||
|
|
||||||
#include "globalconstants.h"
|
#include "globalconstants.h"
|
||||||
|
#include "globals.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -12,7 +12,8 @@
|
|||||||
|
|
||||||
namespace GlobalConstants
|
namespace GlobalConstants
|
||||||
{
|
{
|
||||||
const int GAMEDETAILS_CACHE_VERSION = 1;
|
const int GAMEDETAILS_CACHE_VERSION = 2;
|
||||||
|
const int ZLIB_WINDOW_SIZE = 15;
|
||||||
|
|
||||||
struct optionsStruct {const unsigned int id; const std::string code; const std::string str; const std::string regexp;};
|
struct optionsStruct {const unsigned int id; const std::string code; const std::string str; const std::string regexp;};
|
||||||
const std::string PROTOCOL_PREFIX = "gogdownloader://";
|
const std::string PROTOCOL_PREFIX = "gogdownloader://";
|
||||||
|
21
include/globals.h
Normal file
21
include/globals.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/* This program is free software. It comes without any warranty, to
|
||||||
|
* the extent permitted by applicable law. You can redistribute it
|
||||||
|
* and/or modify it under the terms of the Do What The Fuck You Want
|
||||||
|
* To Public License, Version 2, as published by Sam Hocevar. See
|
||||||
|
* http://www.wtfpl.net/ for more details. */
|
||||||
|
|
||||||
|
#ifndef GLOBALS_H_INCLUDED
|
||||||
|
#define GLOBALS_H_INCLUDED
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Globals
|
||||||
|
{
|
||||||
|
extern GalaxyConfig galaxyConf;
|
||||||
|
extern Config globalConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // GLOBALS_H_INCLUDED
|
||||||
|
|
@ -8,6 +8,8 @@
|
|||||||
#define UTIL_H
|
#define UTIL_H
|
||||||
|
|
||||||
#include "globalconstants.h"
|
#include "globalconstants.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "globals.h"
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
@ -21,29 +23,6 @@
|
|||||||
#include <boost/regex.hpp>
|
#include <boost/regex.hpp>
|
||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
|
|
||||||
struct gameSpecificDirectoryConfig
|
|
||||||
{
|
|
||||||
bool bSubDirectories;
|
|
||||||
std::string sDirectory;
|
|
||||||
std::string sGameSubdir;
|
|
||||||
std::string sInstallersSubdir;
|
|
||||||
std::string sExtrasSubdir;
|
|
||||||
std::string sPatchesSubdir;
|
|
||||||
std::string sLanguagePackSubdir;
|
|
||||||
std::string sDLCSubdir;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct gameSpecificConfig
|
|
||||||
{
|
|
||||||
unsigned int iInstallerPlatform;
|
|
||||||
unsigned int iInstallerLanguage;
|
|
||||||
bool bDLC;
|
|
||||||
bool bIgnoreDLCCount;
|
|
||||||
gameSpecificDirectoryConfig dirConf;
|
|
||||||
std::vector<unsigned int> vLanguagePriority;
|
|
||||||
std::vector<unsigned int> vPlatformPriority;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct gameItem
|
struct gameItem
|
||||||
{
|
{
|
||||||
std::string name;
|
std::string name;
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "globals.h"
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@ -16,7 +17,7 @@
|
|||||||
class Website
|
class Website
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Website(Config &conf);
|
Website();
|
||||||
int Login(const std::string& email, const std::string& password);
|
int Login(const std::string& email, const std::string& password);
|
||||||
std::string getResponse(const std::string& url);
|
std::string getResponse(const std::string& url);
|
||||||
Json::Value getGameDetailsJSON(const std::string& gameid);
|
Json::Value getGameDetailsJSON(const std::string& gameid);
|
||||||
@ -24,7 +25,6 @@ class Website
|
|||||||
std::vector<gameItem> getFreeGames();
|
std::vector<gameItem> getFreeGames();
|
||||||
std::vector<wishlistItem> getWishlistItems();
|
std::vector<wishlistItem> getWishlistItems();
|
||||||
bool IsLoggedIn();
|
bool IsLoggedIn();
|
||||||
void setConfig(Config &conf);
|
|
||||||
virtual ~Website();
|
virtual ~Website();
|
||||||
protected:
|
protected:
|
||||||
private:
|
private:
|
||||||
|
373
main.cpp
373
main.cpp
@ -9,12 +9,15 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "globalconstants.h"
|
#include "globalconstants.h"
|
||||||
#include "ssl_thread_setup.h"
|
#include "ssl_thread_setup.h"
|
||||||
|
#include "galaxyapi.h"
|
||||||
|
#include "globals.h"
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
#include <boost/program_options.hpp>
|
#include <boost/program_options.hpp>
|
||||||
|
|
||||||
namespace bpo = boost::program_options;
|
namespace bpo = boost::program_options;
|
||||||
|
Config Globals::globalConfig;
|
||||||
|
|
||||||
template<typename T> void set_vm_value(std::map<std::string, bpo::variable_value>& vm, const std::string& option, const T& value)
|
template<typename T> void set_vm_value(std::map<std::string, bpo::variable_value>& vm, const std::string& option, const T& value)
|
||||||
{
|
{
|
||||||
@ -44,19 +47,20 @@ int main(int argc, char *argv[])
|
|||||||
{ OPTION_DLCS, "d", "DLCs", "d|dlc|dlcs" }
|
{ OPTION_DLCS, "d", "DLCs", "d|dlc|dlcs" }
|
||||||
};
|
};
|
||||||
|
|
||||||
Config config;
|
Globals::globalConfig.sVersionString = VERSION_STRING;
|
||||||
config.sVersionString = VERSION_STRING;
|
Globals::globalConfig.sVersionNumber = VERSION_NUMBER;
|
||||||
config.sVersionNumber = VERSION_NUMBER;
|
|
||||||
|
|
||||||
config.sCacheDirectory = Util::getCacheHome() + "/lgogdownloader";
|
Globals::globalConfig.sCacheDirectory = Util::getCacheHome() + "/lgogdownloader";
|
||||||
config.sXMLDirectory = config.sCacheDirectory + "/xml";
|
Globals::globalConfig.sXMLDirectory = Globals::globalConfig.sCacheDirectory + "/xml";
|
||||||
|
|
||||||
config.sConfigDirectory = Util::getConfigHome() + "/lgogdownloader";
|
Globals::globalConfig.sConfigDirectory = Util::getConfigHome() + "/lgogdownloader";
|
||||||
config.sCookiePath = config.sConfigDirectory + "/cookies.txt";
|
Globals::globalConfig.curlConf.sCookiePath = Globals::globalConfig.sConfigDirectory + "/cookies.txt";
|
||||||
config.sConfigFilePath = config.sConfigDirectory + "/config.cfg";
|
Globals::globalConfig.sConfigFilePath = Globals::globalConfig.sConfigDirectory + "/config.cfg";
|
||||||
config.sBlacklistFilePath = config.sConfigDirectory + "/blacklist.txt";
|
Globals::globalConfig.sBlacklistFilePath = Globals::globalConfig.sConfigDirectory + "/blacklist.txt";
|
||||||
config.sIgnorelistFilePath = config.sConfigDirectory + "/ignorelist.txt";
|
Globals::globalConfig.sIgnorelistFilePath = Globals::globalConfig.sConfigDirectory + "/ignorelist.txt";
|
||||||
config.sGameHasDLCListFilePath = config.sConfigDirectory + "/game_has_dlc.txt";
|
Globals::globalConfig.sGameHasDLCListFilePath = Globals::globalConfig.sConfigDirectory + "/game_has_dlc.txt";
|
||||||
|
|
||||||
|
Globals::galaxyConf.setFilepath(Globals::globalConfig.sConfigDirectory + "/galaxy_tokens.json");
|
||||||
|
|
||||||
std::string priority_help_text = "Set priority by separating values with \",\"\nCombine values by separating with \"+\"";
|
std::string priority_help_text = "Set priority by separating values with \",\"\nCombine values by separating with \"+\"";
|
||||||
// Create help text for --platform option
|
// Create help text for --platform option
|
||||||
@ -97,12 +101,17 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
include_options_text += "Separate with \",\" to use multiple values";
|
include_options_text += "Separate with \",\" to use multiple values";
|
||||||
|
|
||||||
|
std::string galaxy_product_id_install;
|
||||||
|
std::string galaxy_product_id_show_builds;
|
||||||
|
|
||||||
std::vector<std::string> vFileIdStrings;
|
std::vector<std::string> vFileIdStrings;
|
||||||
std::vector<std::string> unrecognized_options_cfg;
|
std::vector<std::string> unrecognized_options_cfg;
|
||||||
std::vector<std::string> unrecognized_options_cli;
|
std::vector<std::string> unrecognized_options_cli;
|
||||||
bpo::variables_map vm;
|
bpo::variables_map vm;
|
||||||
bpo::options_description options_cli_all("Options");
|
bpo::options_description options_cli_all("Options");
|
||||||
bpo::options_description options_cli_no_cfg;
|
bpo::options_description options_cli_no_cfg;
|
||||||
|
bpo::options_description options_cli_no_cfg_hidden;
|
||||||
|
bpo::options_description options_cli_all_include_hidden;
|
||||||
bpo::options_description options_cli_cfg;
|
bpo::options_description options_cli_cfg;
|
||||||
bpo::options_description options_cfg_only;
|
bpo::options_description options_cfg_only;
|
||||||
bpo::options_description options_cfg_all("Configuration");
|
bpo::options_description options_cfg_all("Configuration");
|
||||||
@ -120,40 +129,40 @@ int main(int argc, char *argv[])
|
|||||||
std::string sInstallerLanguage;
|
std::string sInstallerLanguage;
|
||||||
std::string sIncludeOptions;
|
std::string sIncludeOptions;
|
||||||
std::string sExcludeOptions;
|
std::string sExcludeOptions;
|
||||||
config.bReport = false;
|
Globals::globalConfig.bReport = false;
|
||||||
// Commandline options (no config file)
|
// Commandline options (no config file)
|
||||||
options_cli_no_cfg.add_options()
|
options_cli_no_cfg.add_options()
|
||||||
("help,h", "Print help message")
|
("help,h", "Print help message")
|
||||||
("version", "Print version information")
|
("version", "Print version information")
|
||||||
("login", bpo::value<bool>(&bLogin)->zero_tokens()->default_value(false), "Login")
|
("login", bpo::value<bool>(&bLogin)->zero_tokens()->default_value(false), "Login")
|
||||||
("list", bpo::value<bool>(&config.bList)->zero_tokens()->default_value(false), "List games")
|
("list", bpo::value<bool>(&Globals::globalConfig.bList)->zero_tokens()->default_value(false), "List games")
|
||||||
("list-details", bpo::value<bool>(&config.bListDetails)->zero_tokens()->default_value(false), "List games with detailed info")
|
("list-details", bpo::value<bool>(&Globals::globalConfig.bListDetails)->zero_tokens()->default_value(false), "List games with detailed info")
|
||||||
("download", bpo::value<bool>(&config.bDownload)->zero_tokens()->default_value(false), "Download")
|
("download", bpo::value<bool>(&Globals::globalConfig.bDownload)->zero_tokens()->default_value(false), "Download")
|
||||||
("repair", bpo::value<bool>(&config.bRepair)->zero_tokens()->default_value(false), "Repair downloaded files\nUse --repair --download to redownload files when filesizes don't match (possibly different version). Redownload will rename the old file (appends .old to filename)")
|
("repair", bpo::value<bool>(&Globals::globalConfig.bRepair)->zero_tokens()->default_value(false), "Repair downloaded files\nUse --repair --download to redownload files when filesizes don't match (possibly different version). Redownload will rename the old file (appends .old to filename)")
|
||||||
("game", bpo::value<std::string>(&config.sGameRegex)->default_value(""), "Set regular expression filter\nfor download/list/repair (Perl syntax)\nAliases: \"all\", \"free\"\nAlias \"free\" doesn't work with cached details")
|
("game", bpo::value<std::string>(&Globals::globalConfig.sGameRegex)->default_value(""), "Set regular expression filter\nfor download/list/repair (Perl syntax)\nAliases: \"all\", \"free\"\nAlias \"free\" doesn't work with cached details")
|
||||||
("create-xml", bpo::value<std::string>(&config.sXMLFile)->implicit_value("automatic"), "Create GOG XML for file\n\"automatic\" to enable automatic XML creation")
|
("create-xml", bpo::value<std::string>(&Globals::globalConfig.sXMLFile)->implicit_value("automatic"), "Create GOG XML for file\n\"automatic\" to enable automatic XML creation")
|
||||||
("update-check", bpo::value<bool>(&config.bUpdateCheck)->zero_tokens()->default_value(false), "Check for update notifications")
|
("update-check", bpo::value<bool>(&Globals::globalConfig.bUpdateCheck)->zero_tokens()->default_value(false), "Check for update notifications")
|
||||||
("check-orphans", bpo::value<std::string>(&config.sOrphanRegex)->implicit_value(""), check_orphans_text.c_str())
|
("check-orphans", bpo::value<std::string>(&Globals::globalConfig.sOrphanRegex)->implicit_value(""), check_orphans_text.c_str())
|
||||||
("status", bpo::value<bool>(&config.bCheckStatus)->zero_tokens()->default_value(false), "Show status of files\n\nOutput format:\nstatuscode gamename filename filesize filehash\n\nStatus codes:\nOK - File is OK\nND - File is not downloaded\nMD5 - MD5 mismatch, different version\nFS - File size mismatch, incomplete download")
|
("status", bpo::value<bool>(&Globals::globalConfig.bCheckStatus)->zero_tokens()->default_value(false), "Show status of files\n\nOutput format:\nstatuscode gamename filename filesize filehash\n\nStatus codes:\nOK - File is OK\nND - File is not downloaded\nMD5 - MD5 mismatch, different version\nFS - File size mismatch, incomplete download")
|
||||||
("save-config", bpo::value<bool>(&config.bSaveConfig)->zero_tokens()->default_value(false), "Create config file with current settings")
|
("save-config", bpo::value<bool>(&Globals::globalConfig.bSaveConfig)->zero_tokens()->default_value(false), "Create config file with current settings")
|
||||||
("reset-config", bpo::value<bool>(&config.bResetConfig)->zero_tokens()->default_value(false), "Reset config settings to default")
|
("reset-config", bpo::value<bool>(&Globals::globalConfig.bResetConfig)->zero_tokens()->default_value(false), "Reset config settings to default")
|
||||||
("report", bpo::value<std::string>(&config.sReportFilePath)->implicit_value("lgogdownloader-report.log"), "Save report of downloaded/repaired files to specified file\nDefault filename: lgogdownloader-report.log")
|
("report", bpo::value<std::string>(&Globals::globalConfig.sReportFilePath)->implicit_value("lgogdownloader-report.log"), "Save report of downloaded/repaired files to specified file\nDefault filename: lgogdownloader-report.log")
|
||||||
("update-cache", bpo::value<bool>(&config.bUpdateCache)->zero_tokens()->default_value(false), "Update game details cache")
|
("update-cache", bpo::value<bool>(&Globals::globalConfig.bUpdateCache)->zero_tokens()->default_value(false), "Update game details cache")
|
||||||
("no-platform-detection", bpo::value<bool>(&bNoPlatformDetection)->zero_tokens()->default_value(false), "Don't try to detect supported platforms from game shelf.\nSkips the initial fast platform detection and detects the supported platforms from game details which is slower but more accurate.\nUseful in case platform identifier is missing for some games in the game shelf.\nUsing --platform with --list doesn't work with this option.")
|
("no-platform-detection", bpo::value<bool>(&bNoPlatformDetection)->zero_tokens()->default_value(false), "Don't try to detect supported platforms from game shelf.\nSkips the initial fast platform detection and detects the supported platforms from game details which is slower but more accurate.\nUseful in case platform identifier is missing for some games in the game shelf.\nUsing --platform with --list doesn't work with this option.")
|
||||||
("download-file", bpo::value<std::string>(&config.sFileIdString)->default_value(""), "Download files using fileid\n\nFormat:\n\"gamename/fileid\"\nor: \"gogdownloader://gamename/fileid\"\n\nMultiple files:\n\"gamename1/fileid1,gamename2/fileid2\"\nor: \"gogdownloader://gamename1/fileid1,gamename2/fileid2\"\n\nThis option ignores all subdir options. The files are downloaded to directory specified with --directory option.")
|
("download-file", bpo::value<std::string>(&Globals::globalConfig.sFileIdString)->default_value(""), "Download files using fileid\n\nFormat:\n\"gamename/fileid\"\nor: \"gogdownloader://gamename/fileid\"\n\nMultiple files:\n\"gamename1/fileid1,gamename2/fileid2\"\nor: \"gogdownloader://gamename1/fileid1,gamename2/fileid2\"\n\nThis option ignores all subdir options. The files are downloaded to directory specified with --directory option.")
|
||||||
("output-file,o", bpo::value<std::string>(&config.sOutputFilename)->default_value(""), "Set filename of file downloaded with --download-file.")
|
("output-file,o", bpo::value<std::string>(&Globals::globalConfig.sOutputFilename)->default_value(""), "Set filename of file downloaded with --download-file.")
|
||||||
("wishlist", bpo::value<bool>(&config.bShowWishlist)->zero_tokens()->default_value(false), "Show wishlist")
|
("wishlist", bpo::value<bool>(&Globals::globalConfig.bShowWishlist)->zero_tokens()->default_value(false), "Show wishlist")
|
||||||
("login-api", bpo::value<bool>(&config.bLoginAPI)->zero_tokens()->default_value(false), "Login (API only)")
|
("login-api", bpo::value<bool>(&Globals::globalConfig.bLoginAPI)->zero_tokens()->default_value(false), "Login (API only)")
|
||||||
("login-website", bpo::value<bool>(&config.bLoginHTTP)->zero_tokens()->default_value(false), "Login (website only)")
|
("login-website", bpo::value<bool>(&Globals::globalConfig.bLoginHTTP)->zero_tokens()->default_value(false), "Login (website only)")
|
||||||
("cacert", bpo::value<std::string>(&config.sCACertPath)->default_value(""), "Path to CA certificate bundle in PEM format")
|
("cacert", bpo::value<std::string>(&Globals::globalConfig.curlConf.sCACertPath)->default_value(""), "Path to CA certificate bundle in PEM format")
|
||||||
("respect-umask", bpo::value<bool>(&config.bRespectUmask)->zero_tokens()->default_value(false), "Do not adjust permissions of sensitive files")
|
("respect-umask", bpo::value<bool>(&Globals::globalConfig.bRespectUmask)->zero_tokens()->default_value(false), "Do not adjust permissions of sensitive files")
|
||||||
;
|
;
|
||||||
// Commandline options (config file)
|
// Commandline options (config file)
|
||||||
options_cli_cfg.add_options()
|
options_cli_cfg.add_options()
|
||||||
("directory", bpo::value<std::string>(&config.sDirectory)->default_value("."), "Set download directory")
|
("directory", bpo::value<std::string>(&Globals::globalConfig.dirConf.sDirectory)->default_value("."), "Set download directory")
|
||||||
("limit-rate", bpo::value<curl_off_t>(&config.iDownloadRate)->default_value(0), "Limit download rate to value in kB\n0 = unlimited")
|
("limit-rate", bpo::value<curl_off_t>(&Globals::globalConfig.curlConf.iDownloadRate)->default_value(0), "Limit download rate to value in kB\n0 = unlimited")
|
||||||
("xml-directory", bpo::value<std::string>(&config.sXMLDirectory), "Set directory for GOG XML files")
|
("xml-directory", bpo::value<std::string>(&Globals::globalConfig.sXMLDirectory), "Set directory for GOG XML files")
|
||||||
("chunk-size", bpo::value<size_t>(&config.iChunkSize)->default_value(10), "Chunk size (in MB) when creating XML")
|
("chunk-size", bpo::value<size_t>(&Globals::globalConfig.iChunkSize)->default_value(10), "Chunk size (in MB) when creating XML")
|
||||||
("platform", bpo::value<std::string>(&sInstallerPlatform)->default_value("w+l"), platform_text.c_str())
|
("platform", bpo::value<std::string>(&sInstallerPlatform)->default_value("w+l"), platform_text.c_str())
|
||||||
("language", bpo::value<std::string>(&sInstallerLanguage)->default_value("en"), language_text.c_str())
|
("language", bpo::value<std::string>(&sInstallerLanguage)->default_value("en"), language_text.c_str())
|
||||||
("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")
|
||||||
@ -161,46 +170,52 @@ int main(int argc, char *argv[])
|
|||||||
("no-color", bpo::value<bool>(&bNoColor)->zero_tokens()->default_value(false), "Don't use coloring in the progress bar or status messages")
|
("no-color", bpo::value<bool>(&bNoColor)->zero_tokens()->default_value(false), "Don't use coloring in the progress bar or status messages")
|
||||||
("no-duplicate-handling", bpo::value<bool>(&bNoDuplicateHandler)->zero_tokens()->default_value(false), "Don't use duplicate handler for installers\nDuplicate installers from different languages are handled separately")
|
("no-duplicate-handling", bpo::value<bool>(&bNoDuplicateHandler)->zero_tokens()->default_value(false), "Don't use duplicate handler for installers\nDuplicate installers from different languages are handled separately")
|
||||||
("no-subdirectories", bpo::value<bool>(&bNoSubDirectories)->zero_tokens()->default_value(false), "Don't create subdirectories for extras, patches and language packs")
|
("no-subdirectories", bpo::value<bool>(&bNoSubDirectories)->zero_tokens()->default_value(false), "Don't create subdirectories for extras, patches and language packs")
|
||||||
("verbose", bpo::value<bool>(&config.bVerbose)->zero_tokens()->default_value(false), "Print lots of information")
|
("verbose", bpo::value<bool>(&Globals::globalConfig.bVerbose)->zero_tokens()->default_value(false), "Print lots of information")
|
||||||
("insecure", bpo::value<bool>(&bInsecure)->zero_tokens()->default_value(false), "Don't verify authenticity of SSL certificates")
|
("insecure", bpo::value<bool>(&bInsecure)->zero_tokens()->default_value(false), "Don't verify authenticity of SSL certificates")
|
||||||
("timeout", bpo::value<long int>(&config.iTimeout)->default_value(10), "Set timeout for connection\nMaximum time in seconds that connection phase is allowed to take")
|
("timeout", bpo::value<long int>(&Globals::globalConfig.curlConf.iTimeout)->default_value(10), "Set timeout for connection\nMaximum time in seconds that connection phase is allowed to take")
|
||||||
("retries", bpo::value<int>(&config.iRetries)->default_value(3), "Set maximum number of retries on failed download")
|
("retries", bpo::value<int>(&Globals::globalConfig.iRetries)->default_value(3), "Set maximum number of retries on failed download")
|
||||||
("wait", bpo::value<int>(&config.iWait)->default_value(0), "Time to wait between requests (milliseconds)")
|
("wait", bpo::value<int>(&Globals::globalConfig.iWait)->default_value(0), "Time to wait between requests (milliseconds)")
|
||||||
("cover-list", bpo::value<std::string>(&config.sCoverList)->default_value("https://raw.githubusercontent.com/Sude-/lgogdownloader-lists/master/covers.xml"), "Set URL for cover list")
|
("cover-list", bpo::value<std::string>(&Globals::globalConfig.sCoverList)->default_value("https://raw.githubusercontent.com/Sude-/lgogdownloader-lists/master/covers.xml"), "Set URL for cover list")
|
||||||
("subdir-installers", bpo::value<std::string>(&config.sInstallersSubdir)->default_value(""), ("Set subdirectory for extras" + subdir_help_text).c_str())
|
("subdir-installers", bpo::value<std::string>(&Globals::globalConfig.dirConf.sInstallersSubdir)->default_value(""), ("Set subdirectory for extras" + subdir_help_text).c_str())
|
||||||
("subdir-extras", bpo::value<std::string>(&config.sExtrasSubdir)->default_value("extras"), ("Set subdirectory for extras" + subdir_help_text).c_str())
|
("subdir-extras", bpo::value<std::string>(&Globals::globalConfig.dirConf.sExtrasSubdir)->default_value("extras"), ("Set subdirectory for extras" + subdir_help_text).c_str())
|
||||||
("subdir-patches", bpo::value<std::string>(&config.sPatchesSubdir)->default_value("patches"), ("Set subdirectory for patches" + subdir_help_text).c_str())
|
("subdir-patches", bpo::value<std::string>(&Globals::globalConfig.dirConf.sPatchesSubdir)->default_value("patches"), ("Set subdirectory for patches" + subdir_help_text).c_str())
|
||||||
("subdir-language-packs", bpo::value<std::string>(&config.sLanguagePackSubdir)->default_value("languagepacks"), ("Set subdirectory for language packs" + subdir_help_text).c_str())
|
("subdir-language-packs", bpo::value<std::string>(&Globals::globalConfig.dirConf.sLanguagePackSubdir)->default_value("languagepacks"), ("Set subdirectory for language packs" + subdir_help_text).c_str())
|
||||||
("subdir-dlc", bpo::value<std::string>(&config.sDLCSubdir)->default_value("dlc/%dlcname%"), ("Set subdirectory for dlc" + subdir_help_text).c_str())
|
("subdir-dlc", bpo::value<std::string>(&Globals::globalConfig.dirConf.sDLCSubdir)->default_value("dlc/%dlcname%"), ("Set subdirectory for dlc" + subdir_help_text).c_str())
|
||||||
("subdir-game", bpo::value<std::string>(&config.sGameSubdir)->default_value("%gamename%"), ("Set subdirectory for game" + subdir_help_text).c_str())
|
("subdir-game", bpo::value<std::string>(&Globals::globalConfig.dirConf.sGameSubdir)->default_value("%gamename%"), ("Set subdirectory for game" + subdir_help_text).c_str())
|
||||||
("use-cache", bpo::value<bool>(&config.bUseCache)->zero_tokens()->default_value(false), ("Use game details cache"))
|
("use-cache", bpo::value<bool>(&Globals::globalConfig.bUseCache)->zero_tokens()->default_value(false), ("Use game details cache"))
|
||||||
("cache-valid", bpo::value<int>(&config.iCacheValid)->default_value(2880), ("Set how long cached game details are valid (in minutes)\nDefault: 2880 minutes (48 hours)"))
|
("cache-valid", bpo::value<int>(&Globals::globalConfig.iCacheValid)->default_value(2880), ("Set how long cached game details are valid (in minutes)\nDefault: 2880 minutes (48 hours)"))
|
||||||
("save-serials", bpo::value<bool>(&config.bSaveSerials)->zero_tokens()->default_value(false), "Save serial numbers when downloading")
|
("save-serials", bpo::value<bool>(&Globals::globalConfig.dlConf.bSaveSerials)->zero_tokens()->default_value(false), "Save serial numbers when downloading")
|
||||||
("ignore-dlc-count", bpo::value<std::string>(&config.sIgnoreDLCCountRegex)->implicit_value(".*"), "Set regular expression filter for games to ignore DLC count information\nIgnoring DLC count information helps in situations where the account page doesn't provide accurate information about DLCs")
|
("ignore-dlc-count", bpo::value<std::string>(&Globals::globalConfig.sIgnoreDLCCountRegex)->implicit_value(".*"), "Set regular expression filter for games to ignore DLC count information\nIgnoring DLC count information helps in situations where the account page doesn't provide accurate information about DLCs")
|
||||||
("include", bpo::value<std::string>(&sIncludeOptions)->default_value("all"), ("Select what to download/list/repair\n" + include_options_text).c_str())
|
("include", bpo::value<std::string>(&sIncludeOptions)->default_value("all"), ("Select what to download/list/repair\n" + include_options_text).c_str())
|
||||||
("exclude", bpo::value<std::string>(&sExcludeOptions)->default_value("covers"), ("Select what not to download/list/repair\n" + include_options_text).c_str())
|
("exclude", bpo::value<std::string>(&sExcludeOptions)->default_value("covers"), ("Select what not to download/list/repair\n" + include_options_text).c_str())
|
||||||
("automatic-xml-creation", bpo::value<bool>(&config.bAutomaticXMLCreation)->zero_tokens()->default_value(false), "Automatically create XML data after download has completed")
|
("automatic-xml-creation", bpo::value<bool>(&Globals::globalConfig.dlConf.bAutomaticXMLCreation)->zero_tokens()->default_value(false), "Automatically create XML data after download has completed")
|
||||||
("save-changelogs", bpo::value<bool>(&config.bSaveChangelogs)->zero_tokens()->default_value(false), "Save changelogs when downloading")
|
("save-changelogs", bpo::value<bool>(&Globals::globalConfig.dlConf.bSaveChangelogs)->zero_tokens()->default_value(false), "Save changelogs when downloading")
|
||||||
("threads", bpo::value<unsigned int>(&config.iThreads)->default_value(4), "Number of download threads")
|
("threads", bpo::value<unsigned int>(&Globals::globalConfig.iThreads)->default_value(4), "Number of download threads")
|
||||||
("dlc-list", bpo::value<std::string>(&config.sGameHasDLCList)->default_value("https://raw.githubusercontent.com/Sude-/lgogdownloader-lists/master/game_has_dlc.txt"), "Set URL for list of games that have DLC")
|
("dlc-list", bpo::value<std::string>(&Globals::globalConfig.sGameHasDLCList)->default_value("https://raw.githubusercontent.com/Sude-/lgogdownloader-lists/master/game_has_dlc.txt"), "Set URL for list of games that have DLC")
|
||||||
;
|
;
|
||||||
// Options read from config file
|
// Options read from config file
|
||||||
options_cfg_only.add_options()
|
options_cfg_only.add_options()
|
||||||
("token", bpo::value<std::string>(&config.sToken)->default_value(""), "oauth token")
|
("token", bpo::value<std::string>(&Globals::globalConfig.apiConf.sToken)->default_value(""), "oauth token")
|
||||||
("secret", bpo::value<std::string>(&config.sSecret)->default_value(""), "oauth secret")
|
("secret", bpo::value<std::string>(&Globals::globalConfig.apiConf.sSecret)->default_value(""), "oauth secret")
|
||||||
|
;
|
||||||
|
|
||||||
|
options_cli_no_cfg_hidden.add_options()
|
||||||
|
("galaxy-install", bpo::value<std::string>(&galaxy_product_id_install)->default_value(""), "Install game using product id")
|
||||||
|
("galaxy-show-builds", bpo::value<std::string>(&galaxy_product_id_show_builds)->default_value(""), "Show game builds using product id")
|
||||||
;
|
;
|
||||||
|
|
||||||
options_cli_all.add(options_cli_no_cfg).add(options_cli_cfg);
|
options_cli_all.add(options_cli_no_cfg).add(options_cli_cfg);
|
||||||
options_cfg_all.add(options_cfg_only).add(options_cli_cfg);
|
options_cfg_all.add(options_cfg_only).add(options_cli_cfg);
|
||||||
|
options_cli_all_include_hidden.add(options_cli_all).add(options_cli_no_cfg_hidden);
|
||||||
|
|
||||||
bpo::parsed_options parsed = bpo::parse_command_line(argc, argv, options_cli_all);
|
bpo::parsed_options parsed = bpo::parse_command_line(argc, argv, options_cli_all_include_hidden);
|
||||||
bpo::store(parsed, vm);
|
bpo::store(parsed, vm);
|
||||||
unrecognized_options_cli = bpo::collect_unrecognized(parsed.options, bpo::include_positional);
|
unrecognized_options_cli = bpo::collect_unrecognized(parsed.options, bpo::include_positional);
|
||||||
bpo::notify(vm);
|
bpo::notify(vm);
|
||||||
|
|
||||||
if (vm.count("help"))
|
if (vm.count("help"))
|
||||||
{
|
{
|
||||||
std::cout << config.sVersionString << std::endl
|
std::cout << Globals::globalConfig.sVersionString << std::endl
|
||||||
<< options_cli_all << std::endl;
|
<< options_cli_all << std::endl;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -212,7 +227,7 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create lgogdownloader directories
|
// Create lgogdownloader directories
|
||||||
boost::filesystem::path path = config.sXMLDirectory;
|
boost::filesystem::path path = Globals::globalConfig.sXMLDirectory;
|
||||||
if (!boost::filesystem::exists(path))
|
if (!boost::filesystem::exists(path))
|
||||||
{
|
{
|
||||||
if (!boost::filesystem::create_directories(path))
|
if (!boost::filesystem::create_directories(path))
|
||||||
@ -222,7 +237,7 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
path = config.sConfigDirectory;
|
path = Globals::globalConfig.sConfigDirectory;
|
||||||
if (!boost::filesystem::exists(path))
|
if (!boost::filesystem::exists(path))
|
||||||
{
|
{
|
||||||
if (!boost::filesystem::create_directories(path))
|
if (!boost::filesystem::create_directories(path))
|
||||||
@ -232,7 +247,7 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
path = config.sCacheDirectory;
|
path = Globals::globalConfig.sCacheDirectory;
|
||||||
if (!boost::filesystem::exists(path))
|
if (!boost::filesystem::exists(path))
|
||||||
{
|
{
|
||||||
if (!boost::filesystem::create_directories(path))
|
if (!boost::filesystem::create_directories(path))
|
||||||
@ -242,12 +257,12 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (boost::filesystem::exists(config.sConfigFilePath))
|
if (boost::filesystem::exists(Globals::globalConfig.sConfigFilePath))
|
||||||
{
|
{
|
||||||
std::ifstream ifs(config.sConfigFilePath.c_str());
|
std::ifstream ifs(Globals::globalConfig.sConfigFilePath.c_str());
|
||||||
if (!ifs)
|
if (!ifs)
|
||||||
{
|
{
|
||||||
std::cerr << "Could not open config file: " << config.sConfigFilePath << std::endl;
|
std::cerr << "Could not open config file: " << Globals::globalConfig.sConfigFilePath << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -259,12 +274,12 @@ int main(int argc, char *argv[])
|
|||||||
unrecognized_options_cfg = bpo::collect_unrecognized(parsed.options, bpo::include_positional);
|
unrecognized_options_cfg = bpo::collect_unrecognized(parsed.options, bpo::include_positional);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (boost::filesystem::exists(config.sBlacklistFilePath))
|
if (boost::filesystem::exists(Globals::globalConfig.sBlacklistFilePath))
|
||||||
{
|
{
|
||||||
std::ifstream ifs(config.sBlacklistFilePath.c_str());
|
std::ifstream ifs(Globals::globalConfig.sBlacklistFilePath.c_str());
|
||||||
if (!ifs)
|
if (!ifs)
|
||||||
{
|
{
|
||||||
std::cerr << "Could not open blacklist file: " << config.sBlacklistFilePath << std::endl;
|
std::cerr << "Could not open blacklist file: " << Globals::globalConfig.sBlacklistFilePath << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -276,16 +291,16 @@ int main(int argc, char *argv[])
|
|||||||
std::getline(ifs, line);
|
std::getline(ifs, line);
|
||||||
lines.push_back(std::move(line));
|
lines.push_back(std::move(line));
|
||||||
}
|
}
|
||||||
config.blacklist.initialize(lines);
|
Globals::globalConfig.blacklist.initialize(lines);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (boost::filesystem::exists(config.sIgnorelistFilePath))
|
if (boost::filesystem::exists(Globals::globalConfig.sIgnorelistFilePath))
|
||||||
{
|
{
|
||||||
std::ifstream ifs(config.sIgnorelistFilePath.c_str());
|
std::ifstream ifs(Globals::globalConfig.sIgnorelistFilePath.c_str());
|
||||||
if (!ifs)
|
if (!ifs)
|
||||||
{
|
{
|
||||||
std::cerr << "Could not open ignorelist file: " << config.sIgnorelistFilePath << std::endl;
|
std::cerr << "Could not open ignorelist file: " << Globals::globalConfig.sIgnorelistFilePath << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -297,18 +312,18 @@ int main(int argc, char *argv[])
|
|||||||
std::getline(ifs, line);
|
std::getline(ifs, line);
|
||||||
lines.push_back(std::move(line));
|
lines.push_back(std::move(line));
|
||||||
}
|
}
|
||||||
config.ignorelist.initialize(lines);
|
Globals::globalConfig.ignorelist.initialize(lines);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.sIgnoreDLCCountRegex.empty())
|
if (Globals::globalConfig.sIgnoreDLCCountRegex.empty())
|
||||||
{
|
{
|
||||||
if (boost::filesystem::exists(config.sGameHasDLCListFilePath))
|
if (boost::filesystem::exists(Globals::globalConfig.sGameHasDLCListFilePath))
|
||||||
{
|
{
|
||||||
std::ifstream ifs(config.sGameHasDLCListFilePath.c_str());
|
std::ifstream ifs(Globals::globalConfig.sGameHasDLCListFilePath.c_str());
|
||||||
if (!ifs)
|
if (!ifs)
|
||||||
{
|
{
|
||||||
std::cerr << "Could not open list of games that have dlc: " << config.sGameHasDLCListFilePath << std::endl;
|
std::cerr << "Could not open list of games that have dlc: " << Globals::globalConfig.sGameHasDLCListFilePath << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -320,55 +335,56 @@ int main(int argc, char *argv[])
|
|||||||
std::getline(ifs, line);
|
std::getline(ifs, line);
|
||||||
lines.push_back(std::move(line));
|
lines.push_back(std::move(line));
|
||||||
}
|
}
|
||||||
config.gamehasdlc.initialize(lines);
|
Globals::globalConfig.gamehasdlc.initialize(lines);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vm.count("chunk-size"))
|
if (vm.count("chunk-size"))
|
||||||
config.iChunkSize <<= 20; // Convert chunk size from bytes to megabytes
|
Globals::globalConfig.iChunkSize <<= 20; // Convert chunk size from bytes to megabytes
|
||||||
|
|
||||||
if (vm.count("limit-rate"))
|
if (vm.count("limit-rate"))
|
||||||
config.iDownloadRate <<= 10; // Convert download rate from bytes to kilobytes
|
Globals::globalConfig.curlConf.iDownloadRate <<= 10; // Convert download rate from bytes to kilobytes
|
||||||
|
|
||||||
if (vm.count("check-orphans"))
|
if (vm.count("check-orphans"))
|
||||||
if (config.sOrphanRegex.empty())
|
if (Globals::globalConfig.sOrphanRegex.empty())
|
||||||
config.sOrphanRegex = orphans_regex_default;
|
Globals::globalConfig.sOrphanRegex = orphans_regex_default;
|
||||||
|
|
||||||
if (vm.count("report"))
|
if (vm.count("report"))
|
||||||
config.bReport = true;
|
Globals::globalConfig.bReport = true;
|
||||||
|
|
||||||
if (config.iWait > 0)
|
if (Globals::globalConfig.iWait > 0)
|
||||||
config.iWait *= 1000;
|
Globals::globalConfig.iWait *= 1000;
|
||||||
|
|
||||||
if (config.iThreads < 1)
|
if (Globals::globalConfig.iThreads < 1)
|
||||||
{
|
{
|
||||||
config.iThreads = 1;
|
Globals::globalConfig.iThreads = 1;
|
||||||
set_vm_value(vm, "threads", config.iThreads);
|
set_vm_value(vm, "threads", Globals::globalConfig.iThreads);
|
||||||
}
|
}
|
||||||
|
|
||||||
config.bVerifyPeer = !bInsecure;
|
Globals::globalConfig.curlConf.bVerbose = Globals::globalConfig.bVerbose;
|
||||||
config.bColor = !bNoColor;
|
Globals::globalConfig.curlConf.bVerifyPeer = !bInsecure;
|
||||||
config.bUnicode = !bNoUnicode;
|
Globals::globalConfig.bColor = !bNoColor;
|
||||||
config.bDuplicateHandler = !bNoDuplicateHandler;
|
Globals::globalConfig.bUnicode = !bNoUnicode;
|
||||||
config.bRemoteXML = !bNoRemoteXML;
|
Globals::globalConfig.dlConf.bDuplicateHandler = !bNoDuplicateHandler;
|
||||||
config.bSubDirectories = !bNoSubDirectories;
|
Globals::globalConfig.dlConf.bRemoteXML = !bNoRemoteXML;
|
||||||
config.bPlatformDetection = !bNoPlatformDetection;
|
Globals::globalConfig.dirConf.bSubDirectories = !bNoSubDirectories;
|
||||||
|
Globals::globalConfig.bPlatformDetection = !bNoPlatformDetection;
|
||||||
|
|
||||||
for (auto i = unrecognized_options_cli.begin(); i != unrecognized_options_cli.end(); ++i)
|
for (auto i = unrecognized_options_cli.begin(); i != unrecognized_options_cli.end(); ++i)
|
||||||
if (i->compare(0, GlobalConstants::PROTOCOL_PREFIX.length(), GlobalConstants::PROTOCOL_PREFIX) == 0)
|
if (i->compare(0, GlobalConstants::PROTOCOL_PREFIX.length(), GlobalConstants::PROTOCOL_PREFIX) == 0)
|
||||||
config.sFileIdString = *i;
|
Globals::globalConfig.sFileIdString = *i;
|
||||||
|
|
||||||
if (!config.sFileIdString.empty())
|
if (!Globals::globalConfig.sFileIdString.empty())
|
||||||
{
|
{
|
||||||
if (config.sFileIdString.compare(0, GlobalConstants::PROTOCOL_PREFIX.length(), GlobalConstants::PROTOCOL_PREFIX) == 0)
|
if (Globals::globalConfig.sFileIdString.compare(0, GlobalConstants::PROTOCOL_PREFIX.length(), GlobalConstants::PROTOCOL_PREFIX) == 0)
|
||||||
{
|
{
|
||||||
config.sFileIdString.replace(0, GlobalConstants::PROTOCOL_PREFIX.length(), "");
|
Globals::globalConfig.sFileIdString.replace(0, GlobalConstants::PROTOCOL_PREFIX.length(), "");
|
||||||
}
|
}
|
||||||
vFileIdStrings = Util::tokenize(config.sFileIdString, ",");
|
vFileIdStrings = Util::tokenize(Globals::globalConfig.sFileIdString, ",");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!config.sOutputFilename.empty() && vFileIdStrings.size() > 1)
|
if (!Globals::globalConfig.sOutputFilename.empty() && vFileIdStrings.size() > 1)
|
||||||
{
|
{
|
||||||
std::cerr << "Cannot specify an output file name when downloading multiple files." << std::endl;
|
std::cerr << "Cannot specify an output file name when downloading multiple files." << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
@ -376,15 +392,15 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
if (bLogin)
|
if (bLogin)
|
||||||
{
|
{
|
||||||
config.bLoginAPI = true;
|
Globals::globalConfig.bLoginAPI = true;
|
||||||
config.bLoginHTTP = true;
|
Globals::globalConfig.bLoginHTTP = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.sXMLFile == "automatic")
|
if (Globals::globalConfig.sXMLFile == "automatic")
|
||||||
config.bAutomaticXMLCreation = true;
|
Globals::globalConfig.dlConf.bAutomaticXMLCreation = true;
|
||||||
|
|
||||||
Util::parseOptionString(sInstallerLanguage, config.vLanguagePriority, config.iInstallerLanguage, GlobalConstants::LANGUAGES);
|
Util::parseOptionString(sInstallerLanguage, Globals::globalConfig.dlConf.vLanguagePriority, Globals::globalConfig.dlConf.iInstallerLanguage, GlobalConstants::LANGUAGES);
|
||||||
Util::parseOptionString(sInstallerPlatform, config.vPlatformPriority, config.iInstallerPlatform, GlobalConstants::PLATFORMS);
|
Util::parseOptionString(sInstallerPlatform, Globals::globalConfig.dlConf.vPlatformPriority, Globals::globalConfig.dlConf.iInstallerPlatform, GlobalConstants::PLATFORMS);
|
||||||
|
|
||||||
unsigned int include_value = 0;
|
unsigned int include_value = 0;
|
||||||
unsigned int exclude_value = 0;
|
unsigned int exclude_value = 0;
|
||||||
@ -398,16 +414,16 @@ int main(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
exclude_value |= Util::getOptionValue(*it, INCLUDE_OPTIONS);
|
exclude_value |= Util::getOptionValue(*it, INCLUDE_OPTIONS);
|
||||||
}
|
}
|
||||||
config.iInclude = include_value & ~exclude_value;
|
Globals::globalConfig.dlConf.iInclude = include_value & ~exclude_value;
|
||||||
|
|
||||||
// Assign values
|
// Assign values
|
||||||
// TODO: Use config.iInclude in Downloader class directly and get rid of this value assignment
|
// TODO: Use config.iInclude in Downloader class directly and get rid of this value assignment
|
||||||
config.bCover = (config.iInclude & OPTION_COVERS);
|
Globals::globalConfig.dlConf.bCover = (Globals::globalConfig.dlConf.iInclude & OPTION_COVERS);
|
||||||
config.bInstallers = (config.iInclude & OPTION_INSTALLERS);
|
Globals::globalConfig.dlConf.bInstallers = (Globals::globalConfig.dlConf.iInclude & OPTION_INSTALLERS);
|
||||||
config.bExtras = (config.iInclude & OPTION_EXTRAS);
|
Globals::globalConfig.dlConf.bExtras = (Globals::globalConfig.dlConf.iInclude & OPTION_EXTRAS);
|
||||||
config.bPatches = (config.iInclude & OPTION_PATCHES);
|
Globals::globalConfig.dlConf.bPatches = (Globals::globalConfig.dlConf.iInclude & OPTION_PATCHES);
|
||||||
config.bLanguagePacks = (config.iInclude & OPTION_LANGPACKS);
|
Globals::globalConfig.dlConf.bLanguagePacks = (Globals::globalConfig.dlConf.iInclude & OPTION_LANGPACKS);
|
||||||
config.bDLC = (config.iInclude & OPTION_DLCS);
|
Globals::globalConfig.dlConf.bDLC = (Globals::globalConfig.dlConf.iInclude & OPTION_DLCS);
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
@ -420,55 +436,55 @@ int main(int argc, char *argv[])
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.iInstallerPlatform < GlobalConstants::PLATFORMS[0].id || config.iInstallerPlatform > platform_all)
|
if (Globals::globalConfig.dlConf.iInstallerPlatform < GlobalConstants::PLATFORMS[0].id || Globals::globalConfig.dlConf.iInstallerPlatform > platform_all)
|
||||||
{
|
{
|
||||||
std::cerr << "Invalid value for --platform" << std::endl;
|
std::cerr << "Invalid value for --platform" << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.iInstallerLanguage < GlobalConstants::LANGUAGES[0].id || config.iInstallerLanguage > language_all)
|
if (Globals::globalConfig.dlConf.iInstallerLanguage < GlobalConstants::LANGUAGES[0].id || Globals::globalConfig.dlConf.iInstallerLanguage > language_all)
|
||||||
{
|
{
|
||||||
std::cerr << "Invalid value for --language" << std::endl;
|
std::cerr << "Invalid value for --language" << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!config.sXMLDirectory.empty())
|
if (!Globals::globalConfig.sXMLDirectory.empty())
|
||||||
{
|
{
|
||||||
// Make sure that xml directory doesn't have trailing slash
|
// Make sure that xml directory doesn't have trailing slash
|
||||||
if (config.sXMLDirectory.at(config.sXMLDirectory.length()-1)=='/')
|
if (Globals::globalConfig.sXMLDirectory.at(Globals::globalConfig.sXMLDirectory.length()-1)=='/')
|
||||||
config.sXMLDirectory.assign(config.sXMLDirectory.begin(),config.sXMLDirectory.end()-1);
|
Globals::globalConfig.sXMLDirectory.assign(Globals::globalConfig.sXMLDirectory.begin(), Globals::globalConfig.sXMLDirectory.end()-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create GOG XML for a file
|
// Create GOG XML for a file
|
||||||
if (!config.sXMLFile.empty() && (config.sXMLFile != "automatic"))
|
if (!Globals::globalConfig.sXMLFile.empty() && (Globals::globalConfig.sXMLFile != "automatic"))
|
||||||
{
|
{
|
||||||
Util::createXML(config.sXMLFile, config.iChunkSize, config.sXMLDirectory);
|
Util::createXML(Globals::globalConfig.sXMLFile, Globals::globalConfig.iChunkSize, Globals::globalConfig.sXMLDirectory);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure that directory has trailing slash
|
// Make sure that directory has trailing slash
|
||||||
if (!config.sDirectory.empty())
|
if (!Globals::globalConfig.dirConf.sDirectory.empty())
|
||||||
{
|
{
|
||||||
if (config.sDirectory.at(config.sDirectory.length()-1)!='/')
|
if (Globals::globalConfig.dirConf.sDirectory.at(Globals::globalConfig.dirConf.sDirectory.length()-1)!='/')
|
||||||
config.sDirectory += "/";
|
Globals::globalConfig.dirConf.sDirectory += "/";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
config.sDirectory = "./"; // Directory wasn't specified, use current directory
|
Globals::globalConfig.dirConf.sDirectory = "./"; // Directory wasn't specified, use current directory
|
||||||
}
|
}
|
||||||
|
|
||||||
// CA certificate bundle
|
// CA certificate bundle
|
||||||
if (config.sCACertPath.empty())
|
if (Globals::globalConfig.curlConf.sCACertPath.empty())
|
||||||
{
|
{
|
||||||
// Use CURL_CA_BUNDLE environment variable for CA certificate path if it is set
|
// Use CURL_CA_BUNDLE environment variable for CA certificate path if it is set
|
||||||
char *ca_bundle = getenv("CURL_CA_BUNDLE");
|
char *ca_bundle = getenv("CURL_CA_BUNDLE");
|
||||||
if (ca_bundle)
|
if (ca_bundle)
|
||||||
config.sCACertPath = (std::string)ca_bundle;
|
Globals::globalConfig.curlConf.sCACertPath = (std::string)ca_bundle;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!unrecognized_options_cfg.empty() && (!config.bSaveConfig || !config.bResetConfig))
|
if (!unrecognized_options_cfg.empty() && (!Globals::globalConfig.bSaveConfig || !Globals::globalConfig.bResetConfig))
|
||||||
{
|
{
|
||||||
std::cerr << "Unrecognized options in " << config.sConfigFilePath << std::endl;
|
std::cerr << "Unrecognized options in " << Globals::globalConfig.sConfigFilePath << std::endl;
|
||||||
for (unsigned int i = 0; i < unrecognized_options_cfg.size(); i+=2)
|
for (unsigned int i = 0; i < unrecognized_options_cfg.size(); i+=2)
|
||||||
{
|
{
|
||||||
std::cerr << unrecognized_options_cfg[i] << " = " << unrecognized_options_cfg[i+1] << std::endl;
|
std::cerr << unrecognized_options_cfg[i] << " = " << unrecognized_options_cfg[i+1] << std::endl;
|
||||||
@ -480,25 +496,25 @@ int main(int argc, char *argv[])
|
|||||||
ssl_thread_setup();
|
ssl_thread_setup();
|
||||||
curl_global_init(CURL_GLOBAL_ALL);
|
curl_global_init(CURL_GLOBAL_ALL);
|
||||||
|
|
||||||
if (config.bLoginAPI)
|
if (Globals::globalConfig.bLoginAPI)
|
||||||
{
|
{
|
||||||
config.sToken = "";
|
Globals::globalConfig.apiConf.sToken = "";
|
||||||
config.sSecret = "";
|
Globals::globalConfig.apiConf.sSecret = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
Downloader downloader(config);
|
Downloader downloader;
|
||||||
|
|
||||||
int iLoginTries = 0;
|
int iLoginTries = 0;
|
||||||
bool bLoginOK = false;
|
bool bLoginOK = false;
|
||||||
|
|
||||||
// Login because --login, --login-api or --login-website was used
|
// Login because --login, --login-api or --login-website was used
|
||||||
if (config.bLoginAPI || config.bLoginHTTP)
|
if (Globals::globalConfig.bLoginAPI || Globals::globalConfig.bLoginHTTP)
|
||||||
bLoginOK = downloader.login();
|
bLoginOK = downloader.login();
|
||||||
|
|
||||||
bool bIsLoggedin = downloader.isLoggedIn();
|
bool bIsLoggedin = downloader.isLoggedIn();
|
||||||
|
|
||||||
// Login because we are not logged in
|
// Login because we are not logged in
|
||||||
while (iLoginTries++ < config.iRetries && !bIsLoggedin)
|
while (iLoginTries++ < Globals::globalConfig.iRetries && !bIsLoggedin)
|
||||||
{
|
{
|
||||||
bLoginOK = downloader.login();
|
bLoginOK = downloader.login();
|
||||||
if (bLoginOK)
|
if (bLoginOK)
|
||||||
@ -516,23 +532,24 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Make sure that config file and cookie file are only readable/writable by owner
|
// Make sure that config file and cookie file are only readable/writable by owner
|
||||||
if (!config.bRespectUmask)
|
if (!Globals::globalConfig.bRespectUmask)
|
||||||
{
|
{
|
||||||
Util::setFilePermissions(config.sConfigFilePath, boost::filesystem::owner_read | boost::filesystem::owner_write);
|
Util::setFilePermissions(Globals::globalConfig.sConfigFilePath, boost::filesystem::owner_read | boost::filesystem::owner_write);
|
||||||
Util::setFilePermissions(config.sCookiePath, boost::filesystem::owner_read | boost::filesystem::owner_write);
|
Util::setFilePermissions(Globals::globalConfig.curlConf.sCookiePath, boost::filesystem::owner_read | boost::filesystem::owner_write);
|
||||||
|
Util::setFilePermissions(Globals::galaxyConf.getFilepath(), boost::filesystem::owner_read | boost::filesystem::owner_write);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.bSaveConfig || bLoginOK)
|
if (Globals::globalConfig.bSaveConfig || bLoginOK)
|
||||||
{
|
{
|
||||||
if (bLoginOK)
|
if (bLoginOK)
|
||||||
{
|
{
|
||||||
set_vm_value(vm, "token", downloader.config.sToken);
|
set_vm_value(vm, "token", Globals::globalConfig.apiConf.sToken);
|
||||||
set_vm_value(vm, "secret", downloader.config.sSecret);
|
set_vm_value(vm, "secret", Globals::globalConfig.apiConf.sSecret);
|
||||||
}
|
}
|
||||||
std::ofstream ofs(config.sConfigFilePath.c_str());
|
std::ofstream ofs(Globals::globalConfig.sConfigFilePath.c_str());
|
||||||
if (ofs)
|
if (ofs)
|
||||||
{
|
{
|
||||||
std::cerr << "Saving config: " << config.sConfigFilePath << std::endl;
|
std::cerr << "Saving config: " << Globals::globalConfig.sConfigFilePath << std::endl;
|
||||||
for (bpo::variables_map::iterator it = vm.begin(); it != vm.end(); ++it)
|
for (bpo::variables_map::iterator it = vm.begin(); it != vm.end(); ++it)
|
||||||
{
|
{
|
||||||
std::string option = it->first;
|
std::string option = it->first;
|
||||||
@ -577,9 +594,9 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ofs.close();
|
ofs.close();
|
||||||
if (!config.bRespectUmask)
|
if (!Globals::globalConfig.bRespectUmask)
|
||||||
Util::setFilePermissions(config.sConfigFilePath, boost::filesystem::owner_read | boost::filesystem::owner_write);
|
Util::setFilePermissions(Globals::globalConfig.sConfigFilePath, boost::filesystem::owner_read | boost::filesystem::owner_write);
|
||||||
if (config.bSaveConfig)
|
if (Globals::globalConfig.bSaveConfig)
|
||||||
{
|
{
|
||||||
curl_global_cleanup();
|
curl_global_cleanup();
|
||||||
ssl_thread_cleanup();
|
ssl_thread_cleanup();
|
||||||
@ -588,25 +605,25 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::cerr << "Failed to create config: " << config.sConfigFilePath << std::endl;
|
std::cerr << "Failed to create config: " << Globals::globalConfig.sConfigFilePath << std::endl;
|
||||||
curl_global_cleanup();
|
curl_global_cleanup();
|
||||||
ssl_thread_cleanup();
|
ssl_thread_cleanup();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (config.bResetConfig)
|
else if (Globals::globalConfig.bResetConfig)
|
||||||
{
|
{
|
||||||
std::ofstream ofs(config.sConfigFilePath.c_str());
|
std::ofstream ofs(Globals::globalConfig.sConfigFilePath.c_str());
|
||||||
if (ofs)
|
if (ofs)
|
||||||
{
|
{
|
||||||
if (!config.sToken.empty() && !config.sSecret.empty())
|
if (!Globals::globalConfig.apiConf.sToken.empty() && !Globals::globalConfig.apiConf.sSecret.empty())
|
||||||
{
|
{
|
||||||
ofs << "token = " << config.sToken << std::endl;
|
ofs << "token = " << Globals::globalConfig.apiConf.sToken << std::endl;
|
||||||
ofs << "secret = " << config.sSecret << std::endl;
|
ofs << "secret = " << Globals::globalConfig.apiConf.sSecret << std::endl;
|
||||||
}
|
}
|
||||||
ofs.close();
|
ofs.close();
|
||||||
if (!config.bRespectUmask)
|
if (!Globals::globalConfig.bRespectUmask)
|
||||||
Util::setFilePermissions(config.sConfigFilePath, boost::filesystem::owner_read | boost::filesystem::owner_write);
|
Util::setFilePermissions(Globals::globalConfig.sConfigFilePath, boost::filesystem::owner_read | boost::filesystem::owner_write);
|
||||||
|
|
||||||
curl_global_cleanup();
|
curl_global_cleanup();
|
||||||
ssl_thread_cleanup();
|
ssl_thread_cleanup();
|
||||||
@ -614,7 +631,7 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::cerr << "Failed to create config: " << config.sConfigFilePath << std::endl;
|
std::cerr << "Failed to create config: " << Globals::globalConfig.sConfigFilePath << std::endl;
|
||||||
curl_global_cleanup();
|
curl_global_cleanup();
|
||||||
ssl_thread_cleanup();
|
ssl_thread_cleanup();
|
||||||
return 1;
|
return 1;
|
||||||
@ -631,41 +648,63 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
int res = 0;
|
int res = 0;
|
||||||
|
|
||||||
if (config.bShowWishlist)
|
if (Globals::globalConfig.bShowWishlist)
|
||||||
downloader.showWishlist();
|
downloader.showWishlist();
|
||||||
else if (config.bUpdateCache)
|
else if (Globals::globalConfig.bUpdateCache)
|
||||||
downloader.updateCache();
|
downloader.updateCache();
|
||||||
else if (config.bUpdateCheck) // Update check has priority over download and list
|
else if (Globals::globalConfig.bUpdateCheck) // Update check has priority over download and list
|
||||||
downloader.updateCheck();
|
downloader.updateCheck();
|
||||||
else if (!vFileIdStrings.empty())
|
else if (!vFileIdStrings.empty())
|
||||||
{
|
{
|
||||||
for (std::vector<std::string>::iterator it = vFileIdStrings.begin(); it != vFileIdStrings.end(); it++)
|
for (std::vector<std::string>::iterator it = vFileIdStrings.begin(); it != vFileIdStrings.end(); it++)
|
||||||
{
|
{
|
||||||
res |= downloader.downloadFileWithId(*it, config.sOutputFilename) ? 1 : 0;
|
res |= downloader.downloadFileWithId(*it, Globals::globalConfig.sOutputFilename) ? 1 : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (config.bRepair) // Repair file
|
else if (Globals::globalConfig.bRepair) // Repair file
|
||||||
downloader.repair();
|
downloader.repair();
|
||||||
else if (config.bDownload) // Download games
|
else if (Globals::globalConfig.bDownload) // Download games
|
||||||
downloader.download();
|
downloader.download();
|
||||||
else if (config.bListDetails || config.bList) // Detailed list of games/extras
|
else if (Globals::globalConfig.bListDetails || Globals::globalConfig.bList) // Detailed list of games/extras
|
||||||
res = downloader.listGames();
|
res = downloader.listGames();
|
||||||
else if (!config.sOrphanRegex.empty()) // Check for orphaned files if regex for orphans is set
|
else if (!Globals::globalConfig.sOrphanRegex.empty()) // Check for orphaned files if regex for orphans is set
|
||||||
downloader.checkOrphans();
|
downloader.checkOrphans();
|
||||||
else if (config.bCheckStatus)
|
else if (Globals::globalConfig.bCheckStatus)
|
||||||
downloader.checkStatus();
|
downloader.checkStatus();
|
||||||
|
else if (!galaxy_product_id_show_builds.empty())
|
||||||
|
{
|
||||||
|
int build_index = -1;
|
||||||
|
std::vector<std::string> tokens = Util::tokenize(galaxy_product_id_show_builds, "/");
|
||||||
|
std::string product_id = tokens[0];
|
||||||
|
if (tokens.size() == 2)
|
||||||
|
{
|
||||||
|
build_index = std::stoi(tokens[1]);
|
||||||
|
}
|
||||||
|
downloader.galaxyShowBuilds(product_id, build_index);
|
||||||
|
}
|
||||||
|
else if (!galaxy_product_id_install.empty())
|
||||||
|
{
|
||||||
|
int build_index = -1;
|
||||||
|
std::vector<std::string> tokens = Util::tokenize(galaxy_product_id_install, "/");
|
||||||
|
std::string product_id = tokens[0];
|
||||||
|
if (tokens.size() == 2)
|
||||||
|
{
|
||||||
|
build_index = std::stoi(tokens[1]);
|
||||||
|
}
|
||||||
|
downloader.galaxyInstallGame(product_id, build_index);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!(config.bLoginAPI || config.bLoginHTTP))
|
if (!(Globals::globalConfig.bLoginAPI || Globals::globalConfig.bLoginHTTP))
|
||||||
{
|
{
|
||||||
// Show help message
|
// Show help message
|
||||||
std::cerr << config.sVersionString << std::endl
|
std::cerr << Globals::globalConfig.sVersionString << std::endl
|
||||||
<< options_cli_all << std::endl;
|
<< options_cli_all << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Orphan check was called at the same time as download. Perform it after download has finished
|
// Orphan check was called at the same time as download. Perform it after download has finished
|
||||||
if (!config.sOrphanRegex.empty() && config.bDownload)
|
if (!Globals::globalConfig.sOrphanRegex.empty() && Globals::globalConfig.bDownload)
|
||||||
downloader.checkOrphans();
|
downloader.checkOrphans();
|
||||||
|
|
||||||
curl_global_cleanup();
|
curl_global_cleanup();
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) >= 40900
|
#if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) >= 40900
|
||||||
# define _regex_namespace_ std
|
# define _regex_namespace_ std
|
||||||
@ -150,6 +151,8 @@ int API::login(const std::string& email, const std::string& password)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
usleep(500); // Wait to avoid "429 Too Many Requests"
|
||||||
|
|
||||||
// Authorize temporary token and get verifier
|
// Authorize temporary token and get verifier
|
||||||
url = this->config.oauth_authorize_temp_token + "?username=" + oauth_url_escape(email.c_str()) + "&password=" + oauth_url_escape(password.c_str());
|
url = this->config.oauth_authorize_temp_token + "?username=" + oauth_url_escape(email.c_str()) + "&password=" + oauth_url_escape(password.c_str());
|
||||||
url = oauth_sign_url2(url.c_str(), NULL, OA_HMAC, NULL, CONSUMER_KEY.c_str(), CONSUMER_SECRET.c_str(), token.c_str(), secret.c_str());
|
url = oauth_sign_url2(url.c_str(), NULL, OA_HMAC, NULL, CONSUMER_KEY.c_str(), CONSUMER_SECRET.c_str(), token.c_str(), secret.c_str());
|
||||||
@ -167,6 +170,8 @@ int API::login(const std::string& email, const std::string& password)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
usleep(500); // Wait to avoid "429 Too Many Requests"
|
||||||
|
|
||||||
// Get final token and secret
|
// Get final token and secret
|
||||||
url = this->config.oauth_get_token + "?oauth_verifier=" + verifier;
|
url = this->config.oauth_get_token + "?oauth_verifier=" + verifier;
|
||||||
url = oauth_sign_url2(url.c_str(), NULL, OA_HMAC, NULL, CONSUMER_KEY.c_str(), CONSUMER_SECRET.c_str(), token.c_str(), secret.c_str());
|
url = oauth_sign_url2(url.c_str(), NULL, OA_HMAC, NULL, CONSUMER_KEY.c_str(), CONSUMER_SECRET.c_str(), token.c_str(), secret.c_str());
|
||||||
|
File diff suppressed because it is too large
Load Diff
253
src/galaxyapi.cpp
Normal file
253
src/galaxyapi.cpp
Normal file
@ -0,0 +1,253 @@
|
|||||||
|
/* This program is free software. It comes without any warranty, to
|
||||||
|
* the extent permitted by applicable law. You can redistribute it
|
||||||
|
* and/or modify it under the terms of the Do What The Fuck You Want
|
||||||
|
* To Public License, Version 2, as published by Sam Hocevar. See
|
||||||
|
* http://www.wtfpl.net/ for more details. */
|
||||||
|
|
||||||
|
#include "galaxyapi.h"
|
||||||
|
|
||||||
|
#include <boost/iostreams/filtering_streambuf.hpp>
|
||||||
|
#include <boost/iostreams/copy.hpp>
|
||||||
|
#include <boost/iostreams/filter/zlib.hpp>
|
||||||
|
#include <boost/iostreams/device/back_inserter.hpp>
|
||||||
|
|
||||||
|
GalaxyConfig Globals::galaxyConf;
|
||||||
|
|
||||||
|
size_t galaxyAPI::writeMemoryCallback(char *ptr, size_t size, size_t nmemb, void *userp) {
|
||||||
|
std::ostringstream *stream = (std::ostringstream*)userp;
|
||||||
|
std::streamsize count = (std::streamsize) size * nmemb;
|
||||||
|
stream->write(ptr, count);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
galaxyAPI::galaxyAPI(CurlConfig& conf)
|
||||||
|
{
|
||||||
|
this->curlConf = conf;
|
||||||
|
|
||||||
|
curlhandle = curl_easy_init();
|
||||||
|
curl_easy_setopt(curlhandle, CURLOPT_FOLLOWLOCATION, 1);
|
||||||
|
curl_easy_setopt(curlhandle, CURLOPT_NOPROGRESS, 1);
|
||||||
|
curl_easy_setopt(curlhandle, CURLOPT_PROGRESSDATA, this);
|
||||||
|
curl_easy_setopt(curlhandle, CURLOPT_FAILONERROR, true);
|
||||||
|
curl_easy_setopt(curlhandle, CURLOPT_NOSIGNAL, 1);
|
||||||
|
curl_easy_setopt(curlhandle, CURLOPT_CONNECTTIMEOUT, curlConf.iTimeout);
|
||||||
|
curl_easy_setopt(curlhandle, CURLOPT_FAILONERROR, true);
|
||||||
|
curl_easy_setopt(curlhandle, CURLOPT_COOKIEFILE, curlConf.sCookiePath.c_str());
|
||||||
|
curl_easy_setopt(curlhandle, CURLOPT_COOKIEJAR, curlConf.sCookiePath.c_str());
|
||||||
|
curl_easy_setopt(curlhandle, CURLOPT_SSL_VERIFYPEER, curlConf.bVerifyPeer);
|
||||||
|
curl_easy_setopt(curlhandle, CURLOPT_VERBOSE, curlConf.bVerbose);
|
||||||
|
curl_easy_setopt(curlhandle, CURLOPT_MAX_RECV_SPEED_LARGE, curlConf.iDownloadRate);
|
||||||
|
|
||||||
|
// Assume that we have connection error and abort transfer with CURLE_OPERATION_TIMEDOUT if download speed is less than 200 B/s for 30 seconds
|
||||||
|
curl_easy_setopt(curlhandle, CURLOPT_LOW_SPEED_TIME, 30);
|
||||||
|
curl_easy_setopt(curlhandle, CURLOPT_LOW_SPEED_LIMIT, 200);
|
||||||
|
|
||||||
|
if (!curlConf.sCACertPath.empty())
|
||||||
|
curl_easy_setopt(curlhandle, CURLOPT_CAINFO, curlConf.sCACertPath.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
galaxyAPI::~galaxyAPI()
|
||||||
|
{
|
||||||
|
curl_easy_cleanup(curlhandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize the API
|
||||||
|
returns 0 if failed
|
||||||
|
returns 1 if successful
|
||||||
|
*/
|
||||||
|
int galaxyAPI::init()
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
if (!this->isTokenExpired())
|
||||||
|
{
|
||||||
|
res = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
res = 0;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool galaxyAPI::refreshLogin()
|
||||||
|
{
|
||||||
|
bool res = false;
|
||||||
|
std::string refresh_url = "https://auth.gog.com/token?client_id=" + Globals::galaxyConf.getClientId()
|
||||||
|
+ "&client_secret=" + Globals::galaxyConf.getClientSecret()
|
||||||
|
+ "&grant_type=refresh_token"
|
||||||
|
+ "&refresh_token=" + Globals::galaxyConf.getRefreshToken();
|
||||||
|
|
||||||
|
std::string json = this->getResponse(refresh_url);
|
||||||
|
if (!json.empty())
|
||||||
|
{
|
||||||
|
Json::Value token_json;
|
||||||
|
Json::Reader *jsonparser = new Json::Reader;
|
||||||
|
if (jsonparser->parse(json, token_json))
|
||||||
|
{
|
||||||
|
Globals::galaxyConf.setJSON(token_json);
|
||||||
|
res = true;
|
||||||
|
}
|
||||||
|
delete jsonparser;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool galaxyAPI::isTokenExpired()
|
||||||
|
{
|
||||||
|
int res = false;
|
||||||
|
|
||||||
|
if (Globals::galaxyConf.isExpired())
|
||||||
|
res = true;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string galaxyAPI::getResponse(const std::string& url, const bool& zlib_decompress)
|
||||||
|
{
|
||||||
|
std::ostringstream memory;
|
||||||
|
|
||||||
|
struct curl_slist *header = NULL;
|
||||||
|
|
||||||
|
std::string access_token;
|
||||||
|
if (!Globals::galaxyConf.isExpired())
|
||||||
|
access_token = Globals::galaxyConf.getAccessToken();
|
||||||
|
if (!access_token.empty())
|
||||||
|
{
|
||||||
|
std::string bearer = "Authorization: Bearer " + access_token;
|
||||||
|
header = curl_slist_append(header, bearer.c_str());
|
||||||
|
}
|
||||||
|
curl_easy_setopt(curlhandle, CURLOPT_HTTPHEADER, header);
|
||||||
|
|
||||||
|
curl_easy_setopt(curlhandle, CURLOPT_URL, url.c_str());
|
||||||
|
curl_easy_setopt(curlhandle, CURLOPT_NOPROGRESS, 1);
|
||||||
|
curl_easy_setopt(curlhandle, CURLOPT_WRITEFUNCTION, galaxyAPI::writeMemoryCallback);
|
||||||
|
curl_easy_setopt(curlhandle, CURLOPT_WRITEDATA, &memory);
|
||||||
|
curl_easy_perform(curlhandle);
|
||||||
|
std::string response = memory.str();
|
||||||
|
memory.str(std::string());
|
||||||
|
|
||||||
|
curl_easy_setopt(curlhandle, CURLOPT_HTTPHEADER, NULL);
|
||||||
|
curl_slist_free_all(header);
|
||||||
|
|
||||||
|
if (zlib_decompress)
|
||||||
|
{
|
||||||
|
std::string response_decompressed;
|
||||||
|
boost::iostreams::filtering_streambuf<boost::iostreams::input> in;
|
||||||
|
in.push(boost::iostreams::zlib_decompressor(GlobalConstants::ZLIB_WINDOW_SIZE));
|
||||||
|
in.push(boost::make_iterator_range(response));
|
||||||
|
boost::iostreams::copy(in, boost::iostreams::back_inserter(response_decompressed));
|
||||||
|
response = response_decompressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
Json::Value galaxyAPI::getProductBuilds(const std::string& product_id, const std::string& platform, const std::string& generation)
|
||||||
|
{
|
||||||
|
Json::Value json;
|
||||||
|
|
||||||
|
std::string url = "https://content-system.gog.com/products/" + product_id + "/os/" + platform + "/builds?generation=" + generation;
|
||||||
|
std::string response = this->getResponse(url);
|
||||||
|
|
||||||
|
Json::Reader *jsonparser = new Json::Reader;
|
||||||
|
jsonparser->parse(response, json);
|
||||||
|
delete jsonparser;
|
||||||
|
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
Json::Value galaxyAPI::getManifestV1(const std::string& product_id, const std::string& build_id, const std::string& manifest_id, const std::string& platform)
|
||||||
|
{
|
||||||
|
Json::Value json;
|
||||||
|
|
||||||
|
std::string url = "https://cdn.gog.com/content-system/v1/manifests/" + product_id + "/" + platform + "/" + build_id + "/" + manifest_id + ".json";
|
||||||
|
std::string response = this->getResponse(url);
|
||||||
|
|
||||||
|
Json::Reader *jsonparser = new Json::Reader;
|
||||||
|
jsonparser->parse(response, json);
|
||||||
|
delete jsonparser;
|
||||||
|
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
Json::Value galaxyAPI::getManifestV2(std::string manifest_hash)
|
||||||
|
{
|
||||||
|
Json::Value json;
|
||||||
|
|
||||||
|
if (!manifest_hash.empty() && manifest_hash.find("/") == std::string::npos)
|
||||||
|
manifest_hash = this->hashToGalaxyPath(manifest_hash);
|
||||||
|
|
||||||
|
std::string url = "https://cdn.gog.com/content-system/v2/meta/" + manifest_hash;
|
||||||
|
std::string response = this->getResponse(url, true);
|
||||||
|
|
||||||
|
Json::Reader *jsonparser = new Json::Reader;
|
||||||
|
jsonparser->parse(response, json);
|
||||||
|
delete jsonparser;
|
||||||
|
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
Json::Value galaxyAPI::getSecureLink(const std::string& product_id, const std::string& path)
|
||||||
|
{
|
||||||
|
Json::Value json;
|
||||||
|
|
||||||
|
std::string url = "https://content-system.gog.com/products/" + product_id + "/secure_link?generation=2&path=" + path + "&_version=2";
|
||||||
|
std::string response = this->getResponse(url);
|
||||||
|
|
||||||
|
Json::Reader *jsonparser = new Json::Reader;
|
||||||
|
jsonparser->parse(response, json);
|
||||||
|
delete jsonparser;
|
||||||
|
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string galaxyAPI::hashToGalaxyPath(const std::string& hash)
|
||||||
|
{
|
||||||
|
std::string galaxy_path = hash;
|
||||||
|
if (galaxy_path.find("/") == std::string::npos)
|
||||||
|
galaxy_path.assign(hash.begin(), hash.begin()+2).append("/").append(hash.begin()+2, hash.begin()+4).append("/").append(hash);
|
||||||
|
|
||||||
|
return galaxy_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<galaxyDepotItem> galaxyAPI::getDepotItemsVector(const std::string& hash)
|
||||||
|
{
|
||||||
|
Json::Value json = this->getManifestV2(hash);
|
||||||
|
|
||||||
|
std::vector<galaxyDepotItem> items;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < json["depot"]["items"].size(); ++i)
|
||||||
|
{
|
||||||
|
if (!json["depot"]["items"][i]["chunks"].empty())
|
||||||
|
{
|
||||||
|
galaxyDepotItem item;
|
||||||
|
item.totalSizeCompressed = 0;
|
||||||
|
item.totalSizeUncompressed = 0;
|
||||||
|
item.path = json["depot"]["items"][i]["path"].asString();
|
||||||
|
|
||||||
|
while (Util::replaceString(item.path, "\\", "/"));
|
||||||
|
for (unsigned int j = 0; j < json["depot"]["items"][i]["chunks"].size(); ++j)
|
||||||
|
{
|
||||||
|
galaxyDepotItemChunk chunk;
|
||||||
|
chunk.md5_compressed = json["depot"]["items"][i]["chunks"][j]["compressedMd5"].asString();
|
||||||
|
chunk.md5_uncompressed = json["depot"]["items"][i]["chunks"][j]["md5"].asString();
|
||||||
|
chunk.size_compressed = json["depot"]["items"][i]["chunks"][j]["compressedSize"].asLargestUInt();
|
||||||
|
chunk.size_uncompressed = json["depot"]["items"][i]["chunks"][j]["size"].asLargestUInt();
|
||||||
|
|
||||||
|
item.totalSizeCompressed += chunk.size_compressed;
|
||||||
|
item.totalSizeUncompressed += chunk.size_uncompressed;
|
||||||
|
item.chunks.push_back(chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json["depot"]["items"][i].isMember("md5"))
|
||||||
|
item.md5 = json["depot"]["items"][i]["md5"].asString();
|
||||||
|
else if (json["depot"]["items"][i]["chunks"].size() == 1)
|
||||||
|
item.md5 = json["depot"]["items"][i]["chunks"][0]["md5"].asString();
|
||||||
|
|
||||||
|
items.push_back(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
@ -18,7 +18,7 @@ gameDetails::~gameDetails()
|
|||||||
|
|
||||||
void gameDetails::filterWithPriorities(const gameSpecificConfig& config)
|
void gameDetails::filterWithPriorities(const gameSpecificConfig& config)
|
||||||
{
|
{
|
||||||
if (config.vPlatformPriority.empty() && config.vLanguagePriority.empty())
|
if (config.dlConf.vPlatformPriority.empty() && config.dlConf.vLanguagePriority.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
filterListWithPriorities(installers, config);
|
filterListWithPriorities(installers, config);
|
||||||
@ -40,19 +40,19 @@ void gameDetails::filterListWithPriorities(std::vector<gameFile>& list, const ga
|
|||||||
for (std::vector<gameFile>::iterator fileDetails = list.begin(); fileDetails != list.end(); fileDetails++)
|
for (std::vector<gameFile>::iterator fileDetails = list.begin(); fileDetails != list.end(); fileDetails++)
|
||||||
{
|
{
|
||||||
fileDetails->score = 0;
|
fileDetails->score = 0;
|
||||||
if (!config.vPlatformPriority.empty())
|
if (!config.dlConf.vPlatformPriority.empty())
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i != config.vPlatformPriority.size(); i++)
|
for (size_t i = 0; i != config.dlConf.vPlatformPriority.size(); i++)
|
||||||
if (fileDetails->platform & config.vPlatformPriority[i])
|
if (fileDetails->platform & config.dlConf.vPlatformPriority[i])
|
||||||
{
|
{
|
||||||
fileDetails->score += i;
|
fileDetails->score += i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!config.vLanguagePriority.empty())
|
if (!config.dlConf.vLanguagePriority.empty())
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i != config.vLanguagePriority.size(); i++)
|
for (size_t i = 0; i != config.dlConf.vLanguagePriority.size(); i++)
|
||||||
if (fileDetails->language & config.vLanguagePriority[i])
|
if (fileDetails->language & config.dlConf.vLanguagePriority[i])
|
||||||
{
|
{
|
||||||
fileDetails->score += i;
|
fileDetails->score += i;
|
||||||
break;
|
break;
|
||||||
@ -71,7 +71,7 @@ void gameDetails::filterListWithPriorities(std::vector<gameFile>& list, const ga
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void gameDetails::makeFilepaths(const gameSpecificDirectoryConfig& config)
|
void gameDetails::makeFilepaths(const DirectoryConfig& config)
|
||||||
{
|
{
|
||||||
std::string filepath;
|
std::string filepath;
|
||||||
std::string directory = config.sDirectory + "/" + config.sGameSubdir + "/";
|
std::string directory = config.sDirectory + "/" + config.sGameSubdir + "/";
|
||||||
@ -147,6 +147,7 @@ Json::Value gameDetails::getDetailsAsJson()
|
|||||||
Json::Value json;
|
Json::Value json;
|
||||||
|
|
||||||
json["gamename"] = this->gamename;
|
json["gamename"] = this->gamename;
|
||||||
|
json["product_id"] = this->product_id;
|
||||||
json["title"] = this->title;
|
json["title"] = this->title;
|
||||||
json["icon"] = this->icon;
|
json["icon"] = this->icon;
|
||||||
json["serials"] = this->serials;
|
json["serials"] = this->serials;
|
||||||
|
12
src/util.cpp
12
src/util.cpp
@ -241,31 +241,31 @@ int Util::getGameSpecificConfig(std::string gamename, gameSpecificConfig* conf,
|
|||||||
if (root.isMember("language"))
|
if (root.isMember("language"))
|
||||||
{
|
{
|
||||||
if (root["language"].isInt())
|
if (root["language"].isInt())
|
||||||
conf->iInstallerLanguage = root["language"].asUInt();
|
conf->dlConf.iInstallerLanguage = root["language"].asUInt();
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Util::parseOptionString(root["language"].asString(), conf->vLanguagePriority, conf->iInstallerLanguage, GlobalConstants::LANGUAGES);
|
Util::parseOptionString(root["language"].asString(), conf->dlConf.vLanguagePriority, conf->dlConf.iInstallerLanguage, GlobalConstants::LANGUAGES);
|
||||||
}
|
}
|
||||||
res++;
|
res++;
|
||||||
}
|
}
|
||||||
if (root.isMember("platform"))
|
if (root.isMember("platform"))
|
||||||
{
|
{
|
||||||
if (root["platform"].isInt())
|
if (root["platform"].isInt())
|
||||||
conf->iInstallerPlatform = root["platform"].asUInt();
|
conf->dlConf.iInstallerPlatform = root["platform"].asUInt();
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Util::parseOptionString(root["platform"].asString(), conf->vPlatformPriority, conf->iInstallerPlatform, GlobalConstants::PLATFORMS);
|
Util::parseOptionString(root["platform"].asString(), conf->dlConf.vPlatformPriority, conf->dlConf.iInstallerPlatform, GlobalConstants::PLATFORMS);
|
||||||
}
|
}
|
||||||
res++;
|
res++;
|
||||||
}
|
}
|
||||||
if (root.isMember("dlc"))
|
if (root.isMember("dlc"))
|
||||||
{
|
{
|
||||||
conf->bDLC = root["dlc"].asBool();
|
conf->dlConf.bDLC = root["dlc"].asBool();
|
||||||
res++;
|
res++;
|
||||||
}
|
}
|
||||||
if (root.isMember("ignore-dlc-count"))
|
if (root.isMember("ignore-dlc-count"))
|
||||||
{
|
{
|
||||||
conf->bIgnoreDLCCount = root["ignore-dlc-count"].asBool();
|
conf->dlConf.bIgnoreDLCCount = root["ignore-dlc-count"].asBool();
|
||||||
res++;
|
res++;
|
||||||
}
|
}
|
||||||
if (root.isMember("subdirectories"))
|
if (root.isMember("subdirectories"))
|
||||||
|
272
src/website.cpp
272
src/website.cpp
@ -10,30 +10,29 @@
|
|||||||
#include <htmlcxx/html/ParserDom.h>
|
#include <htmlcxx/html/ParserDom.h>
|
||||||
#include <boost/algorithm/string/case_conv.hpp>
|
#include <boost/algorithm/string/case_conv.hpp>
|
||||||
|
|
||||||
Website::Website(Config &conf)
|
Website::Website()
|
||||||
{
|
{
|
||||||
this->config = conf;
|
|
||||||
this->retries = 0;
|
this->retries = 0;
|
||||||
|
|
||||||
curlhandle = curl_easy_init();
|
curlhandle = curl_easy_init();
|
||||||
curl_easy_setopt(curlhandle, CURLOPT_FOLLOWLOCATION, 1);
|
curl_easy_setopt(curlhandle, CURLOPT_FOLLOWLOCATION, 1);
|
||||||
curl_easy_setopt(curlhandle, CURLOPT_USERAGENT, config.sVersionString.c_str());
|
curl_easy_setopt(curlhandle, CURLOPT_USERAGENT, Globals::globalConfig.sVersionString.c_str());
|
||||||
curl_easy_setopt(curlhandle, CURLOPT_NOPROGRESS, 1);
|
curl_easy_setopt(curlhandle, CURLOPT_NOPROGRESS, 1);
|
||||||
curl_easy_setopt(curlhandle, CURLOPT_NOSIGNAL, 1);
|
curl_easy_setopt(curlhandle, CURLOPT_NOSIGNAL, 1);
|
||||||
curl_easy_setopt(curlhandle, CURLOPT_CONNECTTIMEOUT, config.iTimeout);
|
curl_easy_setopt(curlhandle, CURLOPT_CONNECTTIMEOUT, Globals::globalConfig.curlConf.iTimeout);
|
||||||
curl_easy_setopt(curlhandle, CURLOPT_FAILONERROR, true);
|
curl_easy_setopt(curlhandle, CURLOPT_FAILONERROR, true);
|
||||||
curl_easy_setopt(curlhandle, CURLOPT_COOKIEFILE, config.sCookiePath.c_str());
|
curl_easy_setopt(curlhandle, CURLOPT_COOKIEFILE, Globals::globalConfig.curlConf.sCookiePath.c_str());
|
||||||
curl_easy_setopt(curlhandle, CURLOPT_COOKIEJAR, config.sCookiePath.c_str());
|
curl_easy_setopt(curlhandle, CURLOPT_COOKIEJAR, Globals::globalConfig.curlConf.sCookiePath.c_str());
|
||||||
curl_easy_setopt(curlhandle, CURLOPT_SSL_VERIFYPEER, config.bVerifyPeer);
|
curl_easy_setopt(curlhandle, CURLOPT_SSL_VERIFYPEER, Globals::globalConfig.curlConf.bVerifyPeer);
|
||||||
curl_easy_setopt(curlhandle, CURLOPT_VERBOSE, config.bVerbose);
|
curl_easy_setopt(curlhandle, CURLOPT_VERBOSE, Globals::globalConfig.curlConf.bVerbose);
|
||||||
curl_easy_setopt(curlhandle, CURLOPT_MAX_RECV_SPEED_LARGE, config.iDownloadRate);
|
curl_easy_setopt(curlhandle, CURLOPT_MAX_RECV_SPEED_LARGE, Globals::globalConfig.curlConf.iDownloadRate);
|
||||||
|
|
||||||
// Assume that we have connection error and abort transfer with CURLE_OPERATION_TIMEDOUT if download speed is less than 200 B/s for 30 seconds
|
// Assume that we have connection error and abort transfer with CURLE_OPERATION_TIMEDOUT if download speed is less than 200 B/s for 30 seconds
|
||||||
curl_easy_setopt(curlhandle, CURLOPT_LOW_SPEED_TIME, 30);
|
curl_easy_setopt(curlhandle, CURLOPT_LOW_SPEED_TIME, 30);
|
||||||
curl_easy_setopt(curlhandle, CURLOPT_LOW_SPEED_LIMIT, 200);
|
curl_easy_setopt(curlhandle, CURLOPT_LOW_SPEED_LIMIT, 200);
|
||||||
|
|
||||||
if (!config.sCACertPath.empty())
|
if (!Globals::globalConfig.curlConf.sCACertPath.empty())
|
||||||
curl_easy_setopt(curlhandle, CURLOPT_CAINFO, config.sCACertPath.c_str());
|
curl_easy_setopt(curlhandle, CURLOPT_CAINFO, Globals::globalConfig.curlConf.sCACertPath.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
Website::~Website()
|
Website::~Website()
|
||||||
@ -61,13 +60,13 @@ std::string Website::getResponse(const std::string& url)
|
|||||||
CURLcode result;
|
CURLcode result;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if (config.iWait > 0)
|
if (Globals::globalConfig.iWait > 0)
|
||||||
usleep(config.iWait); // Delay the request by specified time
|
usleep(Globals::globalConfig.iWait); // Delay the request by specified time
|
||||||
result = curl_easy_perform(curlhandle);
|
result = curl_easy_perform(curlhandle);
|
||||||
response = memory.str();
|
response = memory.str();
|
||||||
memory.str(std::string());
|
memory.str(std::string());
|
||||||
}
|
}
|
||||||
while ((result != CURLE_OK) && response.empty() && (this->retries++ < config.iRetries));
|
while ((result != CURLE_OK) && response.empty() && (this->retries++ < Globals::globalConfig.iRetries));
|
||||||
this->retries = 0; // reset retries counter
|
this->retries = 0; // reset retries counter
|
||||||
|
|
||||||
if (result != CURLE_OK)
|
if (result != CURLE_OK)
|
||||||
@ -198,31 +197,31 @@ std::vector<gameItem> Website::getGames()
|
|||||||
platform |= GlobalConstants::PLATFORM_LINUX;
|
platform |= GlobalConstants::PLATFORM_LINUX;
|
||||||
|
|
||||||
// Skip if platform doesn't match
|
// Skip if platform doesn't match
|
||||||
if (config.bPlatformDetection && !(platform & config.iInstallerPlatform))
|
if (Globals::globalConfig.bPlatformDetection && !(platform & Globals::globalConfig.dlConf.iInstallerPlatform))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Filter the game list
|
// Filter the game list
|
||||||
if (!config.sGameRegex.empty())
|
if (!Globals::globalConfig.sGameRegex.empty())
|
||||||
{
|
{
|
||||||
// GameRegex filter aliases
|
// GameRegex filter aliases
|
||||||
if (config.sGameRegex == "all")
|
if (Globals::globalConfig.sGameRegex == "all")
|
||||||
config.sGameRegex = ".*";
|
Globals::globalConfig.sGameRegex = ".*";
|
||||||
|
|
||||||
boost::regex expression(config.sGameRegex);
|
boost::regex expression(Globals::globalConfig.sGameRegex);
|
||||||
boost::match_results<std::string::const_iterator> what;
|
boost::match_results<std::string::const_iterator> what;
|
||||||
if (!boost::regex_search(game.name, what, expression)) // Check if name matches the specified regex
|
if (!boost::regex_search(game.name, what, expression)) // Check if name matches the specified regex
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.bDLC)
|
if (Globals::globalConfig.dlConf.bDLC)
|
||||||
{
|
{
|
||||||
int dlcCount = product["dlcCount"].asInt();
|
int dlcCount = product["dlcCount"].asInt();
|
||||||
|
|
||||||
bool bDownloadDLCInfo = (dlcCount != 0);
|
bool bDownloadDLCInfo = (dlcCount != 0);
|
||||||
|
|
||||||
if (!bDownloadDLCInfo && !config.sIgnoreDLCCountRegex.empty())
|
if (!bDownloadDLCInfo && !Globals::globalConfig.sIgnoreDLCCountRegex.empty())
|
||||||
{
|
{
|
||||||
boost::regex expression(config.sIgnoreDLCCountRegex);
|
boost::regex expression(Globals::globalConfig.sIgnoreDLCCountRegex);
|
||||||
boost::match_results<std::string::const_iterator> what;
|
boost::match_results<std::string::const_iterator> what;
|
||||||
if (boost::regex_search(game.name, what, expression)) // Check if name matches the specified regex
|
if (boost::regex_search(game.name, what, expression)) // Check if name matches the specified regex
|
||||||
{
|
{
|
||||||
@ -230,25 +229,25 @@ std::vector<gameItem> Website::getGames()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bDownloadDLCInfo && !config.gamehasdlc.empty())
|
if (!bDownloadDLCInfo && !Globals::globalConfig.gamehasdlc.empty())
|
||||||
{
|
{
|
||||||
if (config.gamehasdlc.isBlacklisted(game.name))
|
if (Globals::globalConfig.gamehasdlc.isBlacklisted(game.name))
|
||||||
bDownloadDLCInfo = true;
|
bDownloadDLCInfo = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check game specific config
|
// Check game specific config
|
||||||
if (!config.bUpdateCache) // Disable game specific config files for cache update
|
if (!Globals::globalConfig.bUpdateCache) // Disable game specific config files for cache update
|
||||||
{
|
{
|
||||||
gameSpecificConfig conf;
|
gameSpecificConfig conf;
|
||||||
conf.bIgnoreDLCCount = bDownloadDLCInfo;
|
conf.dlConf.bIgnoreDLCCount = bDownloadDLCInfo;
|
||||||
Util::getGameSpecificConfig(game.name, &conf);
|
Util::getGameSpecificConfig(game.name, &conf);
|
||||||
bDownloadDLCInfo = conf.bIgnoreDLCCount;
|
bDownloadDLCInfo = conf.dlConf.bIgnoreDLCCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bDownloadDLCInfo && !config.sGameRegex.empty())
|
if (bDownloadDLCInfo && !Globals::globalConfig.sGameRegex.empty())
|
||||||
{
|
{
|
||||||
// don't download unnecessary info if user is only interested in a subset of his account
|
// don't download unnecessary info if user is only interested in a subset of his account
|
||||||
boost::regex expression(config.sGameRegex);
|
boost::regex expression(Globals::globalConfig.sGameRegex);
|
||||||
boost::match_results<std::string::const_iterator> what;
|
boost::match_results<std::string::const_iterator> what;
|
||||||
if (!boost::regex_search(game.name, what, expression))
|
if (!boost::regex_search(game.name, what, expression))
|
||||||
{
|
{
|
||||||
@ -317,96 +316,40 @@ int Website::Login(const std::string& email, const std::string& password)
|
|||||||
std::string postdata;
|
std::string postdata;
|
||||||
std::ostringstream memory;
|
std::ostringstream memory;
|
||||||
std::string token;
|
std::string token;
|
||||||
std::string tagname_username;
|
std::string tagname_username = "login[username]";
|
||||||
std::string tagname_password;
|
std::string tagname_password = "login[password]";
|
||||||
std::string tagname_login;
|
std::string tagname_login = "login[login]";
|
||||||
std::string tagname_token;
|
std::string tagname_token;
|
||||||
|
std::string auth_url = "https://auth.gog.com/auth?client_id=" + Globals::galaxyConf.getClientId() + "&redirect_uri=" + (std::string)curl_easy_escape(curlhandle, Globals::galaxyConf.getRedirectUri().c_str(), Globals::galaxyConf.getRedirectUri().size()) + "&response_type=code&layout=default&brand=gog";
|
||||||
|
std::string auth_code;
|
||||||
|
|
||||||
// Get login token
|
std::string login_form_html = this->getResponse(auth_url);
|
||||||
std::string html = this->getResponse("https://www.gog.com/");
|
#ifdef DEBUG
|
||||||
htmlcxx::HTML::ParserDom parser;
|
std::cerr << "DEBUG INFO (Website::Login)" << std::endl;
|
||||||
tree<htmlcxx::HTML::Node> dom = parser.parseTree(html);
|
std::cerr << login_form_html << std::endl;
|
||||||
tree<htmlcxx::HTML::Node>::iterator it = dom.begin();
|
#endif
|
||||||
tree<htmlcxx::HTML::Node>::iterator end = dom.end();
|
if (login_form_html.find("google.com/recaptcha") != std::string::npos)
|
||||||
// Find auth_url
|
|
||||||
bool bFoundAuthUrl = false;
|
|
||||||
for (; it != end; ++it)
|
|
||||||
{
|
{
|
||||||
if (it->tagName()=="script")
|
std::cout << "Login form contains reCAPTCHA (https://www.google.com/recaptcha/)" << std::endl
|
||||||
{
|
<< "Login with browser and export cookies to \"" << Globals::globalConfig.curlConf.sCookiePath << "\"" << std::endl;
|
||||||
std::string auth_url;
|
return res = 0;
|
||||||
for (unsigned int i = 0; i < dom.number_of_children(it); ++i)
|
|
||||||
{
|
|
||||||
tree<htmlcxx::HTML::Node>::iterator script_it = dom.child(it, i);
|
|
||||||
if (!script_it->isTag() && !script_it->isComment())
|
|
||||||
{
|
|
||||||
if (script_it->text().find("GalaxyAccounts") != std::string::npos)
|
|
||||||
{
|
|
||||||
boost::match_results<std::string::const_iterator> what;
|
|
||||||
boost::regex expression(".*'(https://auth.gog.com/.*?)'.*");
|
|
||||||
boost::regex_match(script_it->text(), what, expression);
|
|
||||||
auth_url = what[1];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!auth_url.empty())
|
|
||||||
{ // Found auth_url, get the necessary info for login
|
|
||||||
bFoundAuthUrl = true;
|
|
||||||
std::string login_form_html = this->getResponse(auth_url);
|
|
||||||
#ifdef DEBUG
|
|
||||||
std::cerr << "DEBUG INFO (Website::Login)" << std::endl;
|
|
||||||
std::cerr << login_form_html << std::endl;
|
|
||||||
#endif
|
|
||||||
if (login_form_html.find("google.com/recaptcha") != std::string::npos)
|
|
||||||
{
|
|
||||||
std::cout << "Login form contains reCAPTCHA (https://www.google.com/recaptcha/)" << std::endl
|
|
||||||
<< "Login with browser and export cookies to \"" << config.sCookiePath << "\"" << std::endl;
|
|
||||||
return res = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
tree<htmlcxx::HTML::Node> login_dom = parser.parseTree(login_form_html);
|
|
||||||
tree<htmlcxx::HTML::Node>::iterator login_it = login_dom.begin();
|
|
||||||
tree<htmlcxx::HTML::Node>::iterator login_it_end = login_dom.end();
|
|
||||||
for (; login_it != login_it_end; ++login_it)
|
|
||||||
{
|
|
||||||
if (login_it->tagName()=="input")
|
|
||||||
{
|
|
||||||
login_it->parseAttributes();
|
|
||||||
std::string id_login = login_it->attribute("id").second;
|
|
||||||
if (id_login == "login_username")
|
|
||||||
{
|
|
||||||
tagname_username = login_it->attribute("name").second;
|
|
||||||
}
|
|
||||||
else if (id_login == "login_password")
|
|
||||||
{
|
|
||||||
tagname_password = login_it->attribute("name").second;
|
|
||||||
}
|
|
||||||
else if (id_login == "login__token")
|
|
||||||
{
|
|
||||||
token = login_it->attribute("value").second; // login token
|
|
||||||
tagname_token = login_it->attribute("name").second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (login_it->tagName()=="button")
|
|
||||||
{
|
|
||||||
login_it->parseAttributes();
|
|
||||||
std::string id_login = login_it->attribute("id").second;
|
|
||||||
if (id_login == "login_login")
|
|
||||||
{
|
|
||||||
tagname_login = login_it->attribute("name").second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bFoundAuthUrl)
|
htmlcxx::HTML::ParserDom parser;
|
||||||
|
tree<htmlcxx::HTML::Node> login_dom = parser.parseTree(login_form_html);
|
||||||
|
tree<htmlcxx::HTML::Node>::iterator login_it = login_dom.begin();
|
||||||
|
tree<htmlcxx::HTML::Node>::iterator login_it_end = login_dom.end();
|
||||||
|
for (; login_it != login_it_end; ++login_it)
|
||||||
{
|
{
|
||||||
std::cout << "Failed to find url for login form" << std::endl;
|
if (login_it->tagName()=="input")
|
||||||
|
{
|
||||||
|
login_it->parseAttributes();
|
||||||
|
if (login_it->attribute("id").second == "login__token")
|
||||||
|
{
|
||||||
|
token = login_it->attribute("value").second; // login token
|
||||||
|
tagname_token = login_it->attribute("name").second;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (token.empty())
|
if (token.empty())
|
||||||
@ -448,7 +391,14 @@ int Website::Login(const std::string& email, const std::string& password)
|
|||||||
// Handle two step authorization
|
// Handle two step authorization
|
||||||
if (std::string(redirect_url).find("two_step") != std::string::npos)
|
if (std::string(redirect_url).find("two_step") != std::string::npos)
|
||||||
{
|
{
|
||||||
std::string security_code, tagname_two_step_send, tagname_two_step_auth_letter_1, tagname_two_step_auth_letter_2, tagname_two_step_auth_letter_3, tagname_two_step_auth_letter_4, tagname_two_step_token, token_two_step;
|
std::string security_code;
|
||||||
|
std::string tagname_two_step_send = "second_step_authentication[send]";
|
||||||
|
std::string tagname_two_step_auth_letter_1 = "second_step_authentication[token][letter_1]";
|
||||||
|
std::string tagname_two_step_auth_letter_2 = "second_step_authentication[token][letter_2]";
|
||||||
|
std::string tagname_two_step_auth_letter_3 = "second_step_authentication[token][letter_3]";
|
||||||
|
std::string tagname_two_step_auth_letter_4 = "second_step_authentication[token][letter_4]";
|
||||||
|
std::string tagname_two_step_token;
|
||||||
|
std::string token_two_step;
|
||||||
std::string two_step_html = this->getResponse(redirect_url);
|
std::string two_step_html = this->getResponse(redirect_url);
|
||||||
redirect_url = NULL;
|
redirect_url = NULL;
|
||||||
|
|
||||||
@ -460,39 +410,14 @@ int Website::Login(const std::string& email, const std::string& password)
|
|||||||
if (two_step_it->tagName()=="input")
|
if (two_step_it->tagName()=="input")
|
||||||
{
|
{
|
||||||
two_step_it->parseAttributes();
|
two_step_it->parseAttributes();
|
||||||
std::string id_two_step = two_step_it->attribute("id").second;
|
if (two_step_it->attribute("id").second == "second_step_authentication__token")
|
||||||
if (id_two_step == "second_step_authentication_token_letter_1")
|
|
||||||
{
|
|
||||||
tagname_two_step_auth_letter_1 = two_step_it->attribute("name").second;
|
|
||||||
}
|
|
||||||
else if (id_two_step == "second_step_authentication_token_letter_2")
|
|
||||||
{
|
|
||||||
tagname_two_step_auth_letter_2 = two_step_it->attribute("name").second;
|
|
||||||
}
|
|
||||||
else if (id_two_step == "second_step_authentication_token_letter_3")
|
|
||||||
{
|
|
||||||
tagname_two_step_auth_letter_3 = two_step_it->attribute("name").second;
|
|
||||||
}
|
|
||||||
else if (id_two_step == "second_step_authentication_token_letter_4")
|
|
||||||
{
|
|
||||||
tagname_two_step_auth_letter_4 = two_step_it->attribute("name").second;
|
|
||||||
}
|
|
||||||
else if (id_two_step == "second_step_authentication__token")
|
|
||||||
{
|
{
|
||||||
token_two_step = two_step_it->attribute("value").second; // two step token
|
token_two_step = two_step_it->attribute("value").second; // two step token
|
||||||
tagname_two_step_token = two_step_it->attribute("name").second;
|
tagname_two_step_token = two_step_it->attribute("name").second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (two_step_it->tagName()=="button")
|
|
||||||
{
|
|
||||||
two_step_it->parseAttributes();
|
|
||||||
std::string id_two_step = two_step_it->attribute("id").second;
|
|
||||||
if (id_two_step == "second_step_authentication_send")
|
|
||||||
{
|
|
||||||
tagname_two_step_send = two_step_it->attribute("name").second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cerr << "Security code: ";
|
std::cerr << "Security code: ";
|
||||||
std::getline(std::cin,security_code);
|
std::getline(std::cin,security_code);
|
||||||
if (security_code.size() != 4)
|
if (security_code.size() != 4)
|
||||||
@ -500,6 +425,7 @@ int Website::Login(const std::string& email, const std::string& password)
|
|||||||
std::cerr << "Security code must be 4 characters long" << std::endl;
|
std::cerr << "Security code must be 4 characters long" << std::endl;
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
postdata = (std::string)curl_easy_escape(curlhandle, tagname_two_step_auth_letter_1.c_str(), tagname_two_step_auth_letter_1.size()) + "=" + security_code[0]
|
postdata = (std::string)curl_easy_escape(curlhandle, tagname_two_step_auth_letter_1.c_str(), tagname_two_step_auth_letter_1.size()) + "=" + security_code[0]
|
||||||
+ "&" + (std::string)curl_easy_escape(curlhandle, tagname_two_step_auth_letter_2.c_str(), tagname_two_step_auth_letter_2.size()) + "=" + security_code[1]
|
+ "&" + (std::string)curl_easy_escape(curlhandle, tagname_two_step_auth_letter_2.c_str(), tagname_two_step_auth_letter_2.size()) + "=" + security_code[1]
|
||||||
+ "&" + (std::string)curl_easy_escape(curlhandle, tagname_two_step_auth_letter_3.c_str(), tagname_two_step_auth_letter_3.size()) + "=" + security_code[2]
|
+ "&" + (std::string)curl_easy_escape(curlhandle, tagname_two_step_auth_letter_3.c_str(), tagname_two_step_auth_letter_3.size()) + "=" + security_code[2]
|
||||||
@ -523,6 +449,31 @@ int Website::Login(const std::string& email, const std::string& password)
|
|||||||
curl_easy_getinfo(curlhandle, CURLINFO_REDIRECT_URL, &redirect_url);
|
curl_easy_getinfo(curlhandle, CURLINFO_REDIRECT_URL, &redirect_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!std::string(redirect_url).empty())
|
||||||
|
{
|
||||||
|
long response_code;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
curl_easy_setopt(curlhandle, CURLOPT_URL, redirect_url);
|
||||||
|
result = curl_easy_perform(curlhandle);
|
||||||
|
memory.str(std::string());
|
||||||
|
|
||||||
|
result = curl_easy_getinfo(curlhandle, CURLINFO_RESPONSE_CODE, &response_code);
|
||||||
|
if ((response_code / 100) == 3)
|
||||||
|
curl_easy_getinfo(curlhandle, CURLINFO_REDIRECT_URL, &redirect_url);
|
||||||
|
|
||||||
|
std::string redir_url = std::string(redirect_url);
|
||||||
|
boost::regex re(".*code=(.*?)([\?&].*|$)", boost::regex_constants::icase);
|
||||||
|
boost::match_results<std::string::const_iterator> what;
|
||||||
|
if (boost::regex_search(redir_url, what, re))
|
||||||
|
{
|
||||||
|
auth_code = what[1];
|
||||||
|
if (!auth_code.empty())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (result == CURLE_OK && (response_code / 100) == 3);
|
||||||
|
}
|
||||||
|
|
||||||
curl_easy_setopt(curlhandle, CURLOPT_URL, redirect_url);
|
curl_easy_setopt(curlhandle, CURLOPT_URL, redirect_url);
|
||||||
curl_easy_setopt(curlhandle, CURLOPT_HTTPGET, 1);
|
curl_easy_setopt(curlhandle, CURLOPT_HTTPGET, 1);
|
||||||
curl_easy_setopt(curlhandle, CURLOPT_MAXREDIRS, -1);
|
curl_easy_setopt(curlhandle, CURLOPT_MAXREDIRS, -1);
|
||||||
@ -544,11 +495,41 @@ int Website::Login(const std::string& email, const std::string& password)
|
|||||||
res = 1; // Login was successful
|
res = 1; // Login was successful
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (auth_code.empty())
|
||||||
|
res = 0;
|
||||||
|
|
||||||
if (res == 1)
|
if (res == 1)
|
||||||
{
|
{
|
||||||
curl_easy_setopt(curlhandle, CURLOPT_COOKIELIST, "FLUSH"); // Write all known cookies to the file specified by CURLOPT_COOKIEJAR
|
std::string token_url = "https://auth.gog.com/token?client_id=" + Globals::galaxyConf.getClientId()
|
||||||
|
+ "&client_secret=" + Globals::galaxyConf.getClientSecret()
|
||||||
|
+ "&grant_type=authorization_code&code=" + auth_code
|
||||||
|
+ "&redirect_uri=" + (std::string)curl_easy_escape(curlhandle, Globals::galaxyConf.getRedirectUri().c_str(), Globals::galaxyConf.getRedirectUri().size());
|
||||||
|
|
||||||
|
std::string json = this->getResponse(token_url);
|
||||||
|
if (json.empty())
|
||||||
|
res = 0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Json::Value token_json;
|
||||||
|
Json::Reader *jsonparser = new Json::Reader;
|
||||||
|
if (jsonparser->parse(json, token_json))
|
||||||
|
{
|
||||||
|
Globals::galaxyConf.setJSON(token_json);
|
||||||
|
res = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cerr << "Failed to parse json" << std::endl << json << std::endl;
|
||||||
|
std::cerr << jsonparser->getFormattedErrorMessages() << std::endl;
|
||||||
|
res = 0;
|
||||||
|
}
|
||||||
|
delete jsonparser;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (res == 1)
|
||||||
|
curl_easy_setopt(curlhandle, CURLOPT_COOKIELIST, "FLUSH"); // Write all known cookies to the file specified by CURLOPT_COOKIEJAR
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -677,7 +658,7 @@ std::vector<wishlistItem> Website::getWishlistItems()
|
|||||||
item.platform |= GlobalConstants::PLATFORM_LINUX;
|
item.platform |= GlobalConstants::PLATFORM_LINUX;
|
||||||
|
|
||||||
// Skip if platform doesn't match
|
// Skip if platform doesn't match
|
||||||
if (config.bPlatformDetection && !(item.platform & config.iInstallerPlatform))
|
if (Globals::globalConfig.bPlatformDetection && !(item.platform & Globals::globalConfig.dlConf.iInstallerPlatform))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -741,8 +722,3 @@ std::vector<wishlistItem> Website::getWishlistItems()
|
|||||||
|
|
||||||
return wishlistItems;
|
return wishlistItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Website::setConfig(Config &conf)
|
|
||||||
{
|
|
||||||
this->config = conf;
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user