mirror of
https://github.com/Sude-/lgogdownloader.git
synced 2025-02-02 05:52:31 +01:00
Add support for setting subdirectories
Allows user to specify subdirectories for games, installers, extras, patches, language packs and dlc
This commit is contained in:
parent
810506b74b
commit
5635909e20
@ -54,6 +54,12 @@ class Config
|
|||||||
std::string sOrphanRegex;
|
std::string sOrphanRegex;
|
||||||
std::string sCoverList;
|
std::string sCoverList;
|
||||||
std::string sReportFilePath;
|
std::string sReportFilePath;
|
||||||
|
std::string sInstallersSubdir;
|
||||||
|
std::string sExtrasSubdir;
|
||||||
|
std::string sPatchesSubdir;
|
||||||
|
std::string sLanguagePackSubdir;
|
||||||
|
std::string sDLCSubdir;
|
||||||
|
std::string sGameSubdir;
|
||||||
unsigned int iInstallerType;
|
unsigned int iInstallerType;
|
||||||
unsigned int iInstallerLanguage;
|
unsigned int iInstallerLanguage;
|
||||||
int iRetries;
|
int iRetries;
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
#ifndef UTIL_H
|
#ifndef UTIL_H
|
||||||
#define UTIL_H
|
#define UTIL_H
|
||||||
|
|
||||||
|
#include "globalconstants.h"
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@ -24,12 +26,14 @@ struct gameSpecificConfig
|
|||||||
|
|
||||||
namespace Util
|
namespace Util
|
||||||
{
|
{
|
||||||
std::string makeFilepath(const std::string& directory, const std::string& path, const std::string& gamename, std::string subdirectory = "");
|
std::string makeFilepath(const std::string& directory, const std::string& path, const std::string& gamename, std::string subdirectory = "", const unsigned int& platformId = 0, const std::string& dlcname = "");
|
||||||
std::string makeRelativeFilepath(const std::string& path, const std::string& gamename, std::string subdirectory = "");
|
std::string makeRelativeFilepath(const std::string& path, const std::string& gamename, std::string subdirectory = "");
|
||||||
std::string getFileHash(const std::string& filename, unsigned hash_id);
|
std::string getFileHash(const std::string& filename, unsigned hash_id);
|
||||||
std::string getChunkHash(unsigned char* chunk, size_t chunk_size, unsigned hash_id);
|
std::string getChunkHash(unsigned char* chunk, size_t chunk_size, unsigned hash_id);
|
||||||
int createXML(std::string filepath, size_t chunk_size, std::string xml_dir = std::string());
|
int createXML(std::string filepath, size_t chunk_size, std::string xml_dir = std::string());
|
||||||
int getGameSpecificConfig(std::string gamename, gameSpecificConfig* conf, std::string directory = std::string());
|
int getGameSpecificConfig(std::string gamename, gameSpecificConfig* conf, std::string directory = std::string());
|
||||||
|
int replaceString(std::string& str, const std::string& to_replace, const std::string& replace_with);
|
||||||
|
void filepathReplaceReservedStrings(std::string& str, const std::string& gamename, const unsigned int& platformId = 0, const std::string& dlcname = "");
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // UTIL_H
|
#endif // UTIL_H
|
||||||
|
11
main.cpp
11
main.cpp
@ -59,6 +59,9 @@ int main(int argc, char *argv[])
|
|||||||
std::string orphans_regex_default = ".*\\.(zip|exe|bin|dmg|old|deb|tar\\.gz|pkg)$"; // Limit to files with these extensions (".old" is for renamed older version files)
|
std::string orphans_regex_default = ".*\\.(zip|exe|bin|dmg|old|deb|tar\\.gz|pkg)$"; // Limit to files with these extensions (".old" is for renamed older version files)
|
||||||
std::string check_orphans_text = "Check for orphaned files (files found on local filesystem that are not found on GOG servers). Sets regular expression filter (Perl syntax) for files to check. If no argument is given then the regex defaults to '" + orphans_regex_default + "'";
|
std::string check_orphans_text = "Check for orphaned files (files found on local filesystem that are not found on GOG servers). Sets regular expression filter (Perl syntax) for files to check. If no argument is given then the regex defaults to '" + orphans_regex_default + "'";
|
||||||
|
|
||||||
|
// Help text for subdir options
|
||||||
|
std::string subdir_help_text = "\nTemplates:\n- %platform%\n- %gamename%\n- %dlcname%";
|
||||||
|
|
||||||
std::vector<std::string> unrecognized_options_cfg;
|
std::vector<std::string> unrecognized_options_cfg;
|
||||||
bpo::variables_map vm;
|
bpo::variables_map vm;
|
||||||
bpo::options_description options_cli_all("Options");
|
bpo::options_description options_cli_all("Options");
|
||||||
@ -104,7 +107,7 @@ int main(int argc, char *argv[])
|
|||||||
;
|
;
|
||||||
// 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>(&config.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>(&config.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>(&config.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>(&config.iChunkSize)->default_value(10), "Chunk size (in MB) when creating XML")
|
||||||
@ -129,6 +132,12 @@ int main(int argc, char *argv[])
|
|||||||
("retries", bpo::value<int>(&config.iRetries)->default_value(3), "Set maximum number of retries on failed download")
|
("retries", bpo::value<int>(&config.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>(&config.iWait)->default_value(0), "Time to wait between requests (milliseconds)")
|
||||||
("cover-list", bpo::value<std::string>(&config.sCoverList)->default_value("https://sites.google.com/site/gogdownloader/covers.xml"), "Set URL for cover list")
|
("cover-list", bpo::value<std::string>(&config.sCoverList)->default_value("https://sites.google.com/site/gogdownloader/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-extras", bpo::value<std::string>(&config.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-language-packs", bpo::value<std::string>(&config.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-game", bpo::value<std::string>(&config.sGameSubdir)->default_value("%gamename%"), ("Set subdirectory for game" + subdir_help_text).c_str())
|
||||||
;
|
;
|
||||||
// Options read from config file
|
// Options read from config file
|
||||||
options_cfg_only.add_options()
|
options_cfg_only.add_options()
|
||||||
|
@ -2232,19 +2232,48 @@ void Downloader::checkOrphans()
|
|||||||
for (unsigned int i = 0; i < games.size(); ++i)
|
for (unsigned int i = 0; i < games.size(); ++i)
|
||||||
{
|
{
|
||||||
std::cout << "Checking for orphaned files " << i+1 << " / " << games.size() << "\r" << std::flush;
|
std::cout << "Checking for orphaned files " << i+1 << " / " << games.size() << "\r" << std::flush;
|
||||||
boost::filesystem::path path (config.sDirectory + games[i].gamename);
|
|
||||||
std::vector<boost::filesystem::path> filepath_vector;
|
std::vector<boost::filesystem::path> filepath_vector;
|
||||||
std::size_t pathlen = config.sDirectory.length();
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
std::vector<boost::filesystem::path> paths;
|
||||||
|
std::vector<unsigned int> platformIds;
|
||||||
|
platformIds.push_back(0);
|
||||||
|
for (unsigned int j = 0; j < GlobalConstants::PLATFORMS.size(); ++j)
|
||||||
|
{
|
||||||
|
platformIds.push_back(GlobalConstants::PLATFORMS[j].platformId);
|
||||||
|
}
|
||||||
|
for (unsigned int j = 0; j < platformIds.size(); ++j)
|
||||||
|
{
|
||||||
|
std::string directory = config.sDirectory + "/" + config.sGameSubdir + "/";
|
||||||
|
Util::filepathReplaceReservedStrings(directory, games[i].gamename, platformIds[j]);
|
||||||
|
boost::filesystem::path path (directory);
|
||||||
if (boost::filesystem::exists(path))
|
if (boost::filesystem::exists(path))
|
||||||
{
|
{
|
||||||
if (boost::filesystem::is_directory(path))
|
bool bDuplicate = false;
|
||||||
|
for (unsigned int k = 0; k < paths.size(); ++k)
|
||||||
|
{
|
||||||
|
if (path == paths[k])
|
||||||
|
{
|
||||||
|
bDuplicate = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!bDuplicate)
|
||||||
|
paths.push_back(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int j = 0; j < paths.size(); ++j)
|
||||||
|
{
|
||||||
|
std::size_t pathlen = config.sDirectory.length();
|
||||||
|
if (boost::filesystem::exists(paths[j]))
|
||||||
|
{
|
||||||
|
if (boost::filesystem::is_directory(paths[j]))
|
||||||
{
|
{
|
||||||
// Recursively iterate over files in directory
|
// Recursively iterate over files in directory
|
||||||
boost::filesystem::recursive_directory_iterator end_iter;
|
boost::filesystem::recursive_directory_iterator end_iter;
|
||||||
boost::filesystem::recursive_directory_iterator dir_iter(path);
|
boost::filesystem::recursive_directory_iterator dir_iter(paths[j]);
|
||||||
while (dir_iter != end_iter)
|
while (dir_iter != end_iter)
|
||||||
{
|
{
|
||||||
if (boost::filesystem::is_regular_file(dir_iter->status()))
|
if (boost::filesystem::is_regular_file(dir_iter->status()))
|
||||||
@ -2265,7 +2294,8 @@ void Downloader::checkOrphans()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
std::cout << path << " does not exist" << std::endl;
|
std::cout << paths[j] << " does not exist" << std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (const boost::filesystem::filesystem_error& ex)
|
catch (const boost::filesystem::filesystem_error& ex)
|
||||||
{
|
{
|
||||||
|
@ -14,47 +14,56 @@ gameDetails::~gameDetails()
|
|||||||
void gameDetails::makeFilepaths(const Config& config)
|
void gameDetails::makeFilepaths(const Config& config)
|
||||||
{
|
{
|
||||||
std::string filepath;
|
std::string filepath;
|
||||||
|
std::string directory = config.sDirectory + "/" + config.sGameSubdir + "/";
|
||||||
|
std::string subdir;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < this->installers.size(); ++i)
|
for (unsigned int i = 0; i < this->installers.size(); ++i)
|
||||||
{
|
{
|
||||||
filepath = Util::makeFilepath(config.sDirectory, this->installers[i].path, this->gamename);
|
subdir = config.bSubDirectories ? config.sInstallersSubdir : "";
|
||||||
|
filepath = Util::makeFilepath(directory, this->installers[i].path, this->gamename, subdir, this->installers[i].platform);
|
||||||
this->installers[i].setFilepath(filepath);
|
this->installers[i].setFilepath(filepath);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0; i < this->extras.size(); ++i)
|
for (unsigned int i = 0; i < this->extras.size(); ++i)
|
||||||
{
|
{
|
||||||
filepath = Util::makeFilepath(config.sDirectory, this->extras[i].path, this->gamename, config.bSubDirectories ? "extras" : "");
|
subdir = config.bSubDirectories ? config.sExtrasSubdir : "";
|
||||||
|
filepath = Util::makeFilepath(directory, this->extras[i].path, this->gamename, subdir, 0);
|
||||||
this->extras[i].setFilepath(filepath);
|
this->extras[i].setFilepath(filepath);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0; i < this->patches.size(); ++i)
|
for (unsigned int i = 0; i < this->patches.size(); ++i)
|
||||||
{
|
{
|
||||||
filepath = Util::makeFilepath(config.sDirectory, this->patches[i].path, this->gamename, config.bSubDirectories ? "patches" : "");
|
subdir = config.bSubDirectories ? config.sPatchesSubdir : "";
|
||||||
|
filepath = Util::makeFilepath(directory, this->patches[i].path, this->gamename, subdir, this->patches[i].platform);
|
||||||
this->patches[i].setFilepath(filepath);
|
this->patches[i].setFilepath(filepath);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0; i < this->languagepacks.size(); ++i)
|
for (unsigned int i = 0; i < this->languagepacks.size(); ++i)
|
||||||
{
|
{
|
||||||
filepath = Util::makeFilepath(config.sDirectory, this->languagepacks[i].path, this->gamename, config.bSubDirectories ? "languagepacks" : "");
|
subdir = config.bSubDirectories ? config.sLanguagePackSubdir : "";
|
||||||
|
filepath = Util::makeFilepath(directory, this->languagepacks[i].path, this->gamename, subdir, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0; i < this->dlcs.size(); ++i)
|
for (unsigned int i = 0; i < this->dlcs.size(); ++i)
|
||||||
{
|
{
|
||||||
for (unsigned int j = 0; j < this->dlcs[i].installers.size(); ++j)
|
for (unsigned int j = 0; j < this->dlcs[i].installers.size(); ++j)
|
||||||
{
|
{
|
||||||
filepath = Util::makeFilepath(config.sDirectory, this->dlcs[i].installers[j].path, this->gamename, config.bSubDirectories ? "dlc/" + this->dlcs[i].gamename : "");
|
subdir = config.bSubDirectories ? config.sDLCSubdir + "/" + config.sInstallersSubdir : "";
|
||||||
|
filepath = Util::makeFilepath(directory, this->dlcs[i].installers[j].path, this->gamename, subdir, this->dlcs[i].installers[j].platform, this->dlcs[i].gamename);
|
||||||
this->dlcs[i].installers[j].setFilepath(filepath);
|
this->dlcs[i].installers[j].setFilepath(filepath);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int j = 0; j < this->dlcs[i].patches.size(); ++j)
|
for (unsigned int j = 0; j < this->dlcs[i].patches.size(); ++j)
|
||||||
{
|
{
|
||||||
filepath = Util::makeFilepath(config.sDirectory, this->dlcs[i].patches[j].path, this->gamename, config.bSubDirectories ? "dlc/" + this->dlcs[i].gamename + "/patches" : "");
|
subdir = config.bSubDirectories ? config.sDLCSubdir + "/" + config.sPatchesSubdir : "";
|
||||||
|
filepath = Util::makeFilepath(directory, this->dlcs[i].patches[j].path, this->gamename, subdir, this->dlcs[i].patches[j].platform, this->dlcs[i].gamename);
|
||||||
this->dlcs[i].patches[j].setFilepath(filepath);
|
this->dlcs[i].patches[j].setFilepath(filepath);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int j = 0; j < this->dlcs[i].extras.size(); ++j)
|
for (unsigned int j = 0; j < this->dlcs[i].extras.size(); ++j)
|
||||||
{
|
{
|
||||||
filepath = Util::makeFilepath(config.sDirectory, this->dlcs[i].extras[j].path, this->gamename, config.bSubDirectories ? "dlc/" + this->dlcs[i].gamename + "/extras" : "");
|
subdir = config.bSubDirectories ? config.sDLCSubdir + "/" + config.sExtrasSubdir : "";
|
||||||
|
filepath = Util::makeFilepath(directory, this->dlcs[i].extras[j].path, this->gamename, subdir, 0, this->dlcs[i].gamename);
|
||||||
this->dlcs[i].extras[j].setFilepath(filepath);
|
this->dlcs[i].extras[j].setFilepath(filepath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
38
src/util.cpp
38
src/util.cpp
@ -7,6 +7,7 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
|
#include <boost/algorithm/string/case_conv.hpp>
|
||||||
#include <tinyxml.h>
|
#include <tinyxml.h>
|
||||||
#include <jsoncpp/json/json.h>
|
#include <jsoncpp/json/json.h>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@ -16,9 +17,11 @@
|
|||||||
Remove the leading slash from path if needed
|
Remove the leading slash from path if needed
|
||||||
Use gamename as base directory if specified
|
Use gamename as base directory if specified
|
||||||
*/
|
*/
|
||||||
std::string Util::makeFilepath(const std::string& directory, const std::string& path, const std::string& gamename, std::string subdirectory)
|
std::string Util::makeFilepath(const std::string& directory, const std::string& path, const std::string& gamename, std::string subdirectory, const unsigned int& platformId, const std::string& dlcname)
|
||||||
{
|
{
|
||||||
return directory + makeRelativeFilepath(path, gamename, subdirectory);
|
std::string dir = directory + makeRelativeFilepath(path, gamename, subdirectory);
|
||||||
|
Util::filepathReplaceReservedStrings(dir, gamename, platformId, dlcname);
|
||||||
|
return dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create filepath relative to download base directory specified in config.
|
/* Create filepath relative to download base directory specified in config.
|
||||||
@ -46,7 +49,7 @@ std::string Util::makeRelativeFilepath(const std::string& path, const std::strin
|
|||||||
{
|
{
|
||||||
subdirectory = "/" + subdirectory;
|
subdirectory = "/" + subdirectory;
|
||||||
}
|
}
|
||||||
filepath = gamename + subdirectory + "/" + filename;
|
filepath = subdirectory + "/" + filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
return filepath;
|
return filepath;
|
||||||
@ -275,3 +278,32 @@ int Util::getGameSpecificConfig(std::string gamename, gameSpecificConfig* conf,
|
|||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Util::replaceString(std::string& str, const std::string& to_replace, const std::string& replace_with)
|
||||||
|
{
|
||||||
|
size_t pos = str.find(to_replace);
|
||||||
|
if (pos == std::string::npos)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
str.replace(str.begin()+pos, str.begin()+pos+to_replace.length(), replace_with);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Util::filepathReplaceReservedStrings(std::string& str, const std::string& gamename, const unsigned int& platformId, const std::string& dlcname)
|
||||||
|
{
|
||||||
|
std::string platform;
|
||||||
|
while (Util::replaceString(str, "%gamename%", gamename));
|
||||||
|
while (Util::replaceString(str, "%dlcname%", dlcname));
|
||||||
|
for (unsigned int i = 0; i < GlobalConstants::PLATFORMS.size(); ++i)
|
||||||
|
{
|
||||||
|
if ((platformId & GlobalConstants::PLATFORMS[i].platformId) == GlobalConstants::PLATFORMS[i].platformId)
|
||||||
|
{
|
||||||
|
platform = boost::algorithm::to_lower_copy(GlobalConstants::PLATFORMS[i].platformString);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (Util::replaceString(str, "%platform%", platform));
|
||||||
|
while (Util::replaceString(str, "//", "/")); // Replace any double slashes with single slash
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user