Added --status command and made createXML output easier to read

Version check before download now works without local XML data. However it is much slower without the XML data because it calculates MD5 for the files

Some changes to config.h
- Removed "bHelp" from config because it was not needed
- Changed "bNoColor" to "bColor"
- Changed "bNoUnicode" to "bUnicode"
This commit is contained in:
Sude 2013-11-14 15:40:59 +02:00
parent a63165d5a5
commit 0d9c27d20a
4 changed files with 173 additions and 20 deletions

View File

@ -19,7 +19,6 @@ class Config
bool bNoRemoteXML;
bool bNoCover;
bool bUpdateCheck;
bool bHelp;
bool bDownload;
bool bList;
bool bListDetails;
@ -29,10 +28,11 @@ class Config
bool bNoExtras;
bool bNoPatches;
bool bNoLanguagePacks;
bool bNoUnicode; // don't use Unicode in console output
bool bNoColor; // don't use colors
bool bUnicode; // use Unicode in console output
bool bColor; // use colors
bool bVerifyPeer;
bool bCheckOrphans;
bool bCheckStatus;
std::string sGameRegex;
std::string sDirectory;
std::string sXMLFile;

View File

@ -49,6 +49,7 @@ class Downloader
void repair();
void download();
void checkOrphans();
void checkStatus();
CURL* curlhandle;
Timer timer;
Config config;
@ -64,6 +65,8 @@ class Downloader
size_t getResumePosition();
CURLcode beginDownload();
std::string getResponse(const std::string& url);
std::string getLocalFileHash(const std::string& filepath);
std::string getRemoteFileHash(const std::string& gamename, const std::string& id);
int HTTP_Login(const std::string& email, const std::string& password);
std::vector< std::pair<std::string,std::string> > getGames();

View File

@ -76,6 +76,8 @@ int main(int argc, char *argv[])
try
{
bool bInsecure = false;
bool bNoColor = false;
bool bNoUnicode = false;
desc.add_options()
("help,h", "Print help message")
("login", bpo::value<bool>(&config.bLogin)->zero_tokens()->default_value(false), "Login")
@ -98,12 +100,13 @@ int main(int argc, char *argv[])
("no-language-packs", bpo::value<bool>(&config.bNoLanguagePacks)->zero_tokens()->default_value(false), "Don't download/list/repair language packs")
("no-cover", bpo::value<bool>(&config.bNoCover)->zero_tokens()->default_value(false), "Don't download cover images")
("no-remote-xml", bpo::value<bool>(&config.bNoRemoteXML)->zero_tokens()->default_value(false), "Don't use remote XML for repair")
("no-unicode", bpo::value<bool>(&config.bNoUnicode)->zero_tokens()->default_value(false), "Don't use Unicode in the progress bar")
("no-color", bpo::value<bool>(&config.bNoColor)->zero_tokens()->default_value(false), "Don't use coloring in the progress bar")
("no-unicode", bpo::value<bool>(&bNoUnicode)->zero_tokens()->default_value(false), "Don't use Unicode in the progress bar")
("no-color", bpo::value<bool>(&bNoColor)->zero_tokens()->default_value(false), "Don't use coloring in the progress bar")
("verbose", bpo::value<bool>(&config.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")
("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")
("check-orphans", bpo::value<bool>(&config.bCheckOrphans)->zero_tokens()->default_value(false), "Check for orphaned files (files found on local filesystem that are not found on GOG servers)")
("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")
;
bpo::store(bpo::parse_command_line(argc, argv, desc), vm);
@ -145,6 +148,8 @@ int main(int argc, char *argv[])
config.iDownloadRate <<= 10; // Convert download rate from bytes to kilobytes
config.bVerifyPeer = !bInsecure;
config.bColor = !bNoColor;
config.bUnicode = !bNoUnicode;
}
catch (std::exception& e)
{
@ -203,6 +208,8 @@ int main(int argc, char *argv[])
downloader.listGames();
else if (config.bCheckOrphans)
downloader.checkOrphans();
else if (config.bCheckStatus)
downloader.checkStatus();
else
{ // Show help message
std::cout << config.sVersionString << std::endl

View File

@ -69,7 +69,7 @@ int Downloader::init()
gogAPI->curlSetOpt(CURLOPT_SSL_VERIFYPEER, config.bVerifyPeer);
gogAPI->curlSetOpt(CURLOPT_CONNECTTIMEOUT, config.iTimeout);
progressbar = new ProgressBar(!config.bNoUnicode, !config.bNoColor);
progressbar = new ProgressBar(config.bUnicode, config.bColor);
bool bInitOK = gogAPI->init();
if (config.bLogin || !bInitOK)
@ -209,7 +209,7 @@ void Downloader::getGameList()
}
}
if (config.bListDetails || config.bDownload || config.bRepair || config.bCheckOrphans)
if (config.bListDetails || config.bDownload || config.bRepair || config.bCheckOrphans || config.bCheckStatus)
this->getGameDetails();
}
@ -520,6 +520,7 @@ void Downloader::download()
{
std::cout << "Starting automatic XML creation" << std::endl;
Util::createXML(filepath, config.iChunkSize, config.sXMLDirectory);
std::cout << std::endl;
}
}
}
@ -552,6 +553,7 @@ void Downloader::download()
{
std::cout << "Starting automatic XML creation" << std::endl;
Util::createXML(filepath, config.iChunkSize, config.sXMLDirectory);
std::cout << std::endl;
}
}
}
@ -584,6 +586,7 @@ void Downloader::download()
{
std::cout << "Starting automatic XML creation" << std::endl;
Util::createXML(filepath, config.iChunkSize, config.sXMLDirectory);
std::cout << std::endl;
}
}
}
@ -606,30 +609,24 @@ CURLcode Downloader::downloadFile(const std::string& url, const std::string& fil
// Using local XML data for version check before resuming
boost::filesystem::path local_xml_file;
if (config.sXMLDirectory.empty())
local_xml_file = config.sHome + "/.gogdownloader/xml/" + filenameXML;
else
local_xml_file = config.sXMLDirectory + "/" + filenameXML;
local_xml_file = config.sXMLDirectory + "/" + filenameXML;
bool bSameVersion = true; // assume same version
bool bLocalXMLExists = boost::filesystem::exists(local_xml_file);
bool bLocalXMLExists = boost::filesystem::exists(local_xml_file); // This is additional check to see if remote xml should be saved to speed up future version checks
std::string localHash = this->getLocalFileHash(filepath);
if (!xml_data.empty())
{
// Do version check if local XML file exists
if (bLocalXMLExists)
// Do version check if local hash exists
if (!localHash.empty())
{
TiXmlDocument remote_xml, local_xml;
TiXmlDocument remote_xml;
remote_xml.Parse(xml_data.c_str());
local_xml.LoadFile(local_xml_file.string());
TiXmlNode *fileNodeRemote = remote_xml.FirstChild("file");
TiXmlNode *fileNodeLocal = local_xml.FirstChild("file");
if (fileNodeRemote && fileNodeLocal)
if (fileNodeRemote)
{
TiXmlElement *fileElemRemote = fileNodeRemote->ToElement();
TiXmlElement *fileElemLocal = fileNodeLocal->ToElement();
std::string remoteHash = fileElemRemote->Attribute("md5");
std::string localHash = fileElemLocal->Attribute("md5");
if (remoteHash != localHash)
bSameVersion = false;
}
@ -1518,3 +1515,149 @@ void Downloader::checkOrphans()
return;
}
// Check status of files
void Downloader::checkStatus()
{
for (unsigned int i = 0; i < games.size(); ++i)
{
if (!config.bNoInstallers)
{
for (unsigned int j = 0; j < games[i].installers.size(); ++j)
{
boost::filesystem::path filepath = Util::makeFilepath(config.sDirectory, games[i].installers[j].path, games[i].gamename);
std::string remoteHash;
std::string localHash;
bool bHashOK = true; // assume hash OK
size_t filesize;
localHash = this->getLocalFileHash(filepath.string());
remoteHash = this->getRemoteFileHash(games[i].gamename, games[i].installers[j].id);
if (boost::filesystem::exists(filepath))
{
filesize = boost::filesystem::file_size(filepath);
if (remoteHash != localHash)
bHashOK = false;
std::cout << (bHashOK ? "OK " : "MD5 ") << games[i].gamename << " " << filepath.filename().string() << " " << filesize << " " << localHash << std::endl;
}
else
{
std::cout << "ND " << games[i].gamename << " " << filepath.filename().string() << std::endl;
}
}
}
if (!config.bNoExtras)
{
for (unsigned int j = 0; j < games[i].extras.size(); ++j)
{
boost::filesystem::path filepath = Util::makeFilepath(config.sDirectory, games[i].extras[j].path, games[i].gamename);
std::string localHash = this->getLocalFileHash(filepath.string());
size_t filesize;
if (boost::filesystem::exists(filepath))
{
filesize = boost::filesystem::file_size(filepath);
std::cout << "OK " << games[i].gamename << " " << filepath.filename().string() << " " << filesize << " " << localHash << std::endl;
}
else
{
std::cout << "ND " << games[i].gamename << " " << filepath.filename().string() << std::endl;
}
}
}
if (!config.bNoPatches)
{
for (unsigned int j = 0; j < games[i].patches.size(); ++j)
{
boost::filesystem::path filepath = Util::makeFilepath(config.sDirectory, games[i].patches[j].path, games[i].gamename);
std::string localHash = this->getLocalFileHash(filepath.string());
size_t filesize;
if (boost::filesystem::exists(filepath))
{
filesize = boost::filesystem::file_size(filepath);
std::cout << "OK " << games[i].gamename << " " << filepath.filename().string() << " " << filesize << " " << localHash << std::endl;
}
else
{
std::cout << "ND " << games[i].gamename << " " << filepath.filename().string() << std::endl;
}
}
}
if (!config.bNoLanguagePacks)
{
for (unsigned int j = 0; j < games[i].languagepacks.size(); ++j)
{
boost::filesystem::path filepath = Util::makeFilepath(config.sDirectory, games[i].languagepacks[j].path, games[i].gamename);
std::string localHash = this->getLocalFileHash(filepath.string());
size_t filesize;
if (boost::filesystem::exists(filepath))
{
filesize = boost::filesystem::file_size(filepath);
std::cout << "OK " << games[i].gamename << " " << filepath.filename().string() << " " << filesize << " " << localHash << std::endl;
}
else
{
std::cout << "ND " << games[i].gamename << " " << filepath.filename().string() << std::endl;
}
}
}
}
return;
}
std::string Downloader::getLocalFileHash(const std::string& filepath)
{
std::string localHash;
boost::filesystem::path path = filepath;
boost::filesystem::path local_xml_file = config.sXMLDirectory + "/" + path.filename().string() + ".xml";
if (boost::filesystem::exists(local_xml_file))
{
TiXmlDocument local_xml;
local_xml.LoadFile(local_xml_file.string());
TiXmlNode *fileNodeLocal = local_xml.FirstChild("file");
if (fileNodeLocal)
{
TiXmlElement *fileElemLocal = fileNodeLocal->ToElement();
localHash = fileElemLocal->Attribute("md5");
}
}
else
{
if (boost::filesystem::exists(path))
{
localHash = Util::getFileHash(path.string(), RHASH_MD5);
}
}
return localHash;
}
std::string Downloader::getRemoteFileHash(const std::string& gamename, const std::string& id)
{
std::string remoteHash;
std::string xml_data = gogAPI->getXML(gamename, id);
if (!xml_data.empty())
{
TiXmlDocument remote_xml;
remote_xml.Parse(xml_data.c_str());
TiXmlNode *fileNodeRemote = remote_xml.FirstChild("file");
if (fileNodeRemote)
{
TiXmlElement *fileElemRemote = fileNodeRemote->ToElement();
remoteHash = fileElemRemote->Attribute("md5");
}
}
return remoteHash;
}