Add option to transform gamenames

Configuration file $XDG_CONFIG_HOME/lgogdownloader/transformations.json can be used to set rules for transforming gamenames.
New subdir templates: %gamename_transformed% and %gamename_transformed_firstletter%
"--list transformations" can be used to show transformed gamenames
This commit is contained in:
Sude 2023-04-15 22:19:07 +03:00
parent 8a2a6d2071
commit dabfcfc180
6 changed files with 113 additions and 14 deletions

View File

@ -282,6 +282,7 @@ class Config
std::string sIgnorelistFilePath; std::string sIgnorelistFilePath;
std::string sGameHasDLCListFilePath; std::string sGameHasDLCListFilePath;
std::string sReportFilePath; std::string sReportFilePath;
std::string sTransformConfigFilePath;
std::string sXMLFile; std::string sXMLFile;
@ -321,6 +322,8 @@ class Config
int iProgressInterval; int iProgressInterval;
int iMsgLevel; int iMsgLevel;
unsigned int iListFormat; unsigned int iListFormat;
Json::Value transformationsJSON;
}; };
#endif // CONFIG_H__ #endif // CONFIG_H__

View File

@ -118,17 +118,19 @@ namespace GlobalConstants
{ CDN_AKAMAI, "akamai_edgecast_proxy", "Akamai", "akamai|akamai_cdn|akamai_ec|akamai_edgecast_proxy" } { CDN_AKAMAI, "akamai_edgecast_proxy", "Akamai", "akamai|akamai_cdn|akamai_ec|akamai_edgecast_proxy" }
}; };
const unsigned int LIST_FORMAT_GAMES = 1 << 0; const unsigned int LIST_FORMAT_GAMES = 1 << 0;
const unsigned int LIST_FORMAT_DETAILS_TEXT = 1 << 1; const unsigned int LIST_FORMAT_DETAILS_TEXT = 1 << 1;
const unsigned int LIST_FORMAT_DETAILS_JSON = 1 << 2; const unsigned int LIST_FORMAT_DETAILS_JSON = 1 << 2;
const unsigned int LIST_FORMAT_TAGS = 1 << 3; const unsigned int LIST_FORMAT_TAGS = 1 << 3;
const unsigned int LIST_FORMAT_TRANSFORMATIONS = 1 << 4;
const std::vector<optionsStruct> LIST_FORMAT = const std::vector<optionsStruct> LIST_FORMAT =
{ {
{ LIST_FORMAT_GAMES, "games", "Games", "g|games" }, { LIST_FORMAT_GAMES, "games", "Games", "g|games" },
{ LIST_FORMAT_DETAILS_TEXT, "details", "Details", "d|details" }, { LIST_FORMAT_DETAILS_TEXT, "details", "Details", "d|details" },
{ LIST_FORMAT_DETAILS_JSON, "json", "JSON", "j|json" }, { LIST_FORMAT_DETAILS_JSON, "json", "JSON", "j|json" },
{ LIST_FORMAT_TAGS, "tags", "Tags", "t|tags" } { LIST_FORMAT_TAGS, "tags", "Tags", "t|tags" },
{ LIST_FORMAT_TRANSFORMATIONS, "transform", "Transformations", "tr|transform|transformations" }
}; };
} }

View File

@ -79,6 +79,7 @@ int main(int argc, char *argv[])
Globals::globalConfig.sBlacklistFilePath = Globals::globalConfig.sConfigDirectory + "/blacklist.txt"; Globals::globalConfig.sBlacklistFilePath = Globals::globalConfig.sConfigDirectory + "/blacklist.txt";
Globals::globalConfig.sIgnorelistFilePath = Globals::globalConfig.sConfigDirectory + "/ignorelist.txt"; Globals::globalConfig.sIgnorelistFilePath = Globals::globalConfig.sConfigDirectory + "/ignorelist.txt";
Globals::globalConfig.sGameHasDLCListFilePath = Globals::globalConfig.sConfigDirectory + "/game_has_dlc.txt"; Globals::globalConfig.sGameHasDLCListFilePath = Globals::globalConfig.sConfigDirectory + "/game_has_dlc.txt";
Globals::globalConfig.sTransformConfigFilePath = Globals::globalConfig.sConfigDirectory + "/transformations.json";
Globals::galaxyConf.setFilepath(Globals::globalConfig.sConfigDirectory + "/galaxy_tokens.json"); Globals::galaxyConf.setFilepath(Globals::globalConfig.sConfigDirectory + "/galaxy_tokens.json");
@ -151,7 +152,7 @@ int main(int argc, char *argv[])
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 // Help text for subdir options
std::string subdir_help_text = "\nTemplates:\n- %platform%\n- %gamename%\n- %gamename_firstletter%\n- %dlcname%"; std::string subdir_help_text = "\nTemplates:\n- %platform%\n- %gamename%\n- %gamename_firstletter%\n- %dlcname%\n- %gamename_transformed%\n- %gamename_transformed_firstletter%";
// Help text for include and exclude options // Help text for include and exclude options
std::string include_options_text; std::string include_options_text;
@ -432,6 +433,25 @@ int main(int argc, char *argv[])
} }
} }
if (boost::filesystem::exists(Globals::globalConfig.sTransformConfigFilePath))
{
std::ifstream ifs(Globals::globalConfig.sTransformConfigFilePath, std::ifstream::binary);
Json::Value json;
try {
ifs >> json;
if (!json.empty())
{
Globals::globalConfig.transformationsJSON = json;
}
} catch (const Json::Exception& exc) {
std::cerr << "Failed to parse " << Globals::globalConfig.sTransformConfigFilePath<< std::endl;
std::cerr << exc.what() << std::endl;
}
if (ifs)
ifs.close();
}
if (!bUseDLCList) if (!bUseDLCList)
Globals::globalConfig.sGameHasDLCList = ""; Globals::globalConfig.sGameHasDLCList = "";

View File

@ -109,6 +109,42 @@ Must be in the following format:
.br .br
} }
.TP
\fI$XDG_CONFIG_HOME/lgogdownloader/transformations.json\fP
JSON formatted file. Used to transform gamenames.
.br
Must be in the following format:
.br
{
<string> :
{
"regex" : <string>,
"replacement" : <string>,
},
<string> :
{
"regex" : <string>,
"replacement" : <string>,
},
.br
}
.br
Member names are used to match the gamename.
If it matches then \fBregex\fP is used for the actual replacement using the value in \fBreplacement\fP.
.br
\fBExample:\fP
.br
match all games beginning with "\fBb\fP" and if they end with "\fB_the\fP" then remove "\fB_the\fP" at the end and prefix it with "\fBthe_\fP"
.br
{
"^b" :
{
"regex" : "(.*)_the$",
"replacement" : "the_\\\\1",
},
.br
}
[priorities] [priorities]
Separating values with "," when using \fBlanguage\fP and \fBplatform\fP switches enables a priority-based mode: only the first matching one will be downloaded. Separating values with "," when using \fBlanguage\fP and \fBplatform\fP switches enables a priority-based mode: only the first matching one will be downloaded.
.PP .PP

View File

@ -526,7 +526,8 @@ int Downloader::getGameDetails()
int Downloader::listGames() int Downloader::listGames()
{ {
if (Globals::globalConfig.iListFormat == GlobalConstants::LIST_FORMAT_GAMES) if (Globals::globalConfig.iListFormat == GlobalConstants::LIST_FORMAT_GAMES ||
Globals::globalConfig.iListFormat == GlobalConstants::LIST_FORMAT_TRANSFORMATIONS)
{ {
if (gameItems.empty()) if (gameItems.empty())
this->getGameList(); this->getGameList();
@ -534,15 +535,24 @@ int Downloader::listGames()
for (unsigned int i = 0; i < gameItems.size(); ++i) for (unsigned int i = 0; i < gameItems.size(); ++i)
{ {
std::string gamename = gameItems[i].name; std::string gamename = gameItems[i].name;
if (gameItems[i].updates > 0) if (Globals::globalConfig.iListFormat == GlobalConstants::LIST_FORMAT_TRANSFORMATIONS)
{ {
gamename += " [" + std::to_string(gameItems[i].updates) + "]"; std::string str = "%gamename% -> %gamename_transformed%";
if (Globals::globalConfig.bColor) Util::filepathReplaceReservedStrings(str, gamename);
gamename = "\033[32m" + gamename + "\033[0m"; std::cout << str << std::endl;
}
else
{
if (gameItems[i].updates > 0)
{
gamename += " [" + std::to_string(gameItems[i].updates) + "]";
if (Globals::globalConfig.bColor)
gamename = "\033[32m" + gamename + "\033[0m";
}
std::cout << gamename << std::endl;
for (unsigned int j = 0; j < gameItems[i].dlcnames.size(); ++j)
std::cout << "+> " << gameItems[i].dlcnames[j] << std::endl;
} }
std::cout << gamename << std::endl;
for (unsigned int j = 0; j < gameItems[i].dlcnames.size(); ++j)
std::cout << "+> " << gameItems[i].dlcnames[j] << std::endl;
} }
} }
else if (Globals::globalConfig.iListFormat == GlobalConstants::LIST_FORMAT_TAGS) else if (Globals::globalConfig.iListFormat == GlobalConstants::LIST_FORMAT_TAGS)

View File

@ -438,6 +438,34 @@ void Util::filepathReplaceReservedStrings(std::string& str, const std::string& g
gamename_firstletter = gamename.front(); gamename_firstletter = gamename.front();
} }
std::string gamename_transformed = gamename;
if (str.find("%gamename_transformed%") != std::string::npos || str.find("%gamename_transformed_firstletter%") != std::string::npos)
{
for (auto transformMatch : Globals::globalConfig.transformationsJSON.getMemberNames())
{
boost::regex expression(transformMatch);
boost::match_results<std::string::const_iterator> what;
if (boost::regex_search(gamename, what, expression))
{
boost::regex transformRegex(Globals::globalConfig.transformationsJSON[transformMatch]["regex"].asString());
std::string transformReplacement = Globals::globalConfig.transformationsJSON[transformMatch]["replacement"].asString();
gamename_transformed = boost::regex_replace(gamename, transformRegex, transformReplacement);
}
}
std::string gamename_transformed_firstletter;
if (!gamename_transformed.empty())
{
if (std::isdigit(gamename_transformed.front()))
gamename_transformed_firstletter = "0";
else
gamename_transformed_firstletter = gamename_transformed.front();
}
while (Util::replaceString(str, "%gamename_transformed%", gamename_transformed));
while (Util::replaceString(str, "%gamename_transformed_firstletter%", gamename_transformed_firstletter));
}
while (Util::replaceString(str, "%gamename_firstletter%", gamename_firstletter)); while (Util::replaceString(str, "%gamename_firstletter%", gamename_firstletter));
while (Util::replaceString(str, "%gamename%", gamename)); while (Util::replaceString(str, "%gamename%", gamename));
while (Util::replaceString(str, "%dlcname%", dlcname)); while (Util::replaceString(str, "%dlcname%", dlcname));