This commit is contained in:
Sude 2014-10-28 13:38:36 +02:00
commit bddde5b0da
8 changed files with 131 additions and 3 deletions

View File

@ -63,6 +63,11 @@ class Config
std::string sLanguagePackSubdir;
std::string sDLCSubdir;
std::string sGameSubdir;
std::string sLanguagePriority;
std::string sPlatformPriority;
std::vector<unsigned int> vLanguagePriority;
std::vector<unsigned int> vPlatformPriority;
unsigned int iInstallerType;
unsigned int iInstallerLanguage;
int iRetries;

View File

@ -21,10 +21,12 @@ class gameDetails
std::string gamename;
std::string title;
std::string icon;;
void filterWithPriorities(const Config& config);
void makeFilepaths(const Config& config);
Json::Value getDetailsAsJson();
virtual ~gameDetails();
protected:
void filterListWithPriorities(std::vector<gameFile>& list, const Config& config);
private:
};

View File

@ -19,6 +19,7 @@ class gameFile
std::string size;
unsigned int platform;
unsigned int language;
int score;
int silent;
void setFilepath(const std::string& path);
std::string getFilepath();

View File

@ -26,6 +26,40 @@ template<typename T> void set_vm_value(std::map<std::string, bpo::variable_value
vm[option].value() = boost::any(value);
}
// Parse the priority string, making it an array of numeric codes, and override the ORed type if required
void handle_priority(const std::string &what, const std::string &priority_string, std::vector<unsigned int> &priority, unsigned int &type)
{
size_t idx = 0, found;
while ((found = priority_string.find(',', idx)) != std::string::npos)
{
priority.push_back(std::stoi(priority_string.substr(idx, found - idx)));
idx = found + 1;
}
priority.push_back(std::stoi(priority_string.substr(idx)));
unsigned int wanted = 0;
#ifdef DEBUG
std::cerr << "DEBUG INFO (handle_priority): for " << what << " found ";
#endif
for (std::vector<unsigned int>::iterator it = priority.begin(); it != priority.end(); it++)
{
wanted += *it;
#ifdef DEBUG
std::cerr << *it << " ";
#endif
}
#ifdef DEBUG
std::cerr << std::endl;
#endif
if (wanted != type)
{
type = wanted;
std::cout << "Warning: for " << what << " the priority string doesn't match the enabled installers, forcing enabled installers to " << type << std::endl;
}
}
int main(int argc, char *argv[])
{
Config config;
@ -68,6 +102,8 @@ int main(int argc, char *argv[])
// Help text for subdir options
std::string subdir_help_text = "\nTemplates:\n- %platform%\n- %gamename%\n- %dlcname%";
// Help text for priority options
std::string priority_help_text = "\nIf set, only the first matching one will be downloaded. If unset, all matching combinations will be downloaded.\nSyntax: use a string separated by \",\"";
std::vector<std::string> unrecognized_options_cfg;
bpo::variables_map vm;
@ -148,6 +184,9 @@ int main(int argc, char *argv[])
("subdir-game", bpo::value<std::string>(&config.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"))
("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)"))
("language-priority", bpo::value<std::string>(&config.sLanguagePriority)->default_value(""), ("Set priority of systems" + priority_help_text + ", like \"4,1\" for French first, then English if no French version").c_str())
("platform-priority", bpo::value<std::string>(&config.sPlatformPriority)->default_value(""), ("Set priority of platforms" + priority_help_text + ", like \"4,1\" for Linux first, then Windows if no Linux version").c_str())
;
// Options read from config file
options_cfg_only.add_options()
@ -300,6 +339,13 @@ int main(int argc, char *argv[])
// Override cover option
if (bNoCover)
config.bCover = false;
// Handle priority business
if (!config.sLanguagePriority.empty())
handle_priority("languages", config.sLanguagePriority, config.vLanguagePriority, config.iInstallerLanguage);
if (!config.sPlatformPriority.empty())
handle_priority("platforms", config.sPlatformPriority, config.vPlatformPriority, config.iInstallerType);
}
catch (std::exception& e)
{

View File

@ -83,5 +83,16 @@ Must be in the following format:
.br
}
[priorities]
For both languages and platforms, the default behavior is to download all enabled ones.
The \fBlanguage-priority\fB and \fBplatform-priority\fB switches enable a priority-based mode: only the first matching one will be downloaded.
.PP
For example, setting \fBlanguage\fB to 5 means both French and English will be downloaded (if available) for all games. Setting \fBlanguage-priority\fB to 4,1 means that the French version (and only that one) will be downloaded if available, and if not, the English version will be downloaded.
.PP
You're allowed to "stack" codes in the priority string if needed. If you set \fBlanguage-priority\fB 132,1 it means it'll download both Spanish (128) and French (4) versions if they are available, and the English (1) one only if none of French and Spanish are available.
.PP
Ideally the \fBlanguage\fB and \fBplatform\fB settings should match the sum of all enabled codes in the "priority" versions. If they don't, they'll be overrided with a warning.
[availability]
The latest version of this distribution is available from \fIhttps://github.com/Sude-/lgogdownloader\fP

View File

@ -518,9 +518,9 @@ gameDetails API::getGameDetails(const std::string& game_name, const unsigned int
if (!langpacknames.empty()) // found at least one language pack
{
for (unsigned int i = 0; i < langpacknames.size(); ++i)
for (unsigned int j = 0; j < langpacknames.size(); ++j)
{
Json::Value langpack = root["game"][langpacknames[i]];
Json::Value langpack = root["game"][langpacknames[j]];
game.languagepacks.push_back(
gameFile( false, /* language packs don't have "updated" flag */
langpack["id"].isInt() ? std::to_string(langpack["id"].asInt()) : langpack["id"].asString(),

View File

@ -252,6 +252,8 @@ int Downloader::getGameDetails()
game = gogAPI->getGameDetails(gameItems[i].name, conf.iInstallerType, conf.iInstallerLanguage, config.bDuplicateHandler);
if (!gogAPI->getError())
{
game.filterWithPriorities(config);
if (game.extras.empty() && config.bExtras) // Try to get extras from account page if API didn't return any extras
{
game.extras = this->getExtras(gameItems[i].name, gameItems[i].id);
@ -262,6 +264,7 @@ int Downloader::getGameDetails()
{
gameDetails dlc;
dlc = gogAPI->getGameDetails(gameItems[i].dlcnames[j], conf.iInstallerType, conf.iInstallerLanguage, config.bDuplicateHandler);
dlc.filterWithPriorities(config);
if (dlc.extras.empty() && config.bExtras) // Try to get extras from account page if API didn't return any extras
{
dlc.extras = this->getExtras(gameItems[i].dlcnames[j], gameItems[i].id);
@ -2817,8 +2820,11 @@ std::vector<gameDetails> Downloader::getGameDetailsFromJsonNode(Json::Value root
}
}
if (!game.extras.empty() || !game.installers.empty() || !game.patches.empty() || !game.languagepacks.empty() || !game.dlcs.empty())
{
game.filterWithPriorities(config);
details.push_back(game);
}
}
return details;
}
@ -2840,6 +2846,8 @@ void Downloader::updateCache()
config.sGameRegex = ".*";
config.iInstallerLanguage = all_languages;
config.iInstallerType = all_platforms;
config.vLanguagePriority.clear();
config.vPlatformPriority.clear();
this->getGameList();
this->getGameDetails();

View File

@ -11,6 +11,61 @@ gameDetails::~gameDetails()
//dtor
}
void gameDetails::filterWithPriorities(const Config& config)
{
if (config.vPlatformPriority.empty() && config.vLanguagePriority.empty())
return;
filterListWithPriorities(installers, config);
filterListWithPriorities(patches, config);
filterListWithPriorities(languagepacks, config);
}
void gameDetails::filterListWithPriorities(std::vector<gameFile>& list, const Config& config)
{
/*
Compute the score of each item - we use a scoring mechanism and we keep all ties
Like if someone asked French then English and Linux then Windows, but there are
only Windows French, Windows English and Linux English versions, we'll get the
Windows French and Linux English ones.
Score is inverted: lower is better.
*/
int bestscore = -1;
for (std::vector<gameFile>::iterator fileDetails = list.begin(); fileDetails != list.end(); fileDetails++)
{
fileDetails->score = 0;
if (!config.vPlatformPriority.empty())
{
for (size_t i = 0; i != config.vPlatformPriority.size(); i++)
if (fileDetails->platform & config.vPlatformPriority[i])
{
fileDetails->score += i;
break;
}
}
if (!config.vLanguagePriority.empty())
{
for (size_t i = 0; i != config.vLanguagePriority.size(); i++)
if (fileDetails->language & config.vLanguagePriority[i])
{
fileDetails->score += i;
break;
}
}
if ((fileDetails->score < bestscore) or (bestscore < 0))
bestscore = fileDetails->score;
}
for (std::vector<gameFile>::iterator fileDetails = list.begin(); fileDetails != list.end(); )
{
if (fileDetails->score > bestscore)
fileDetails = list.erase(fileDetails);
else
fileDetails++;
}
}
void gameDetails::makeFilepaths(const Config& config)
{
std::string filepath;