// SPDX-License-Identifier: MIT // // ES-DE Frontend // MetaData.cpp // // Static data for default metadata values as well as functions // to read and write metadata from the gamelist files. // #include "MetaData.h" #include "Log.h" #include "utils/FileSystemUtil.h" #include "utils/LocalizationUtil.h" #include namespace { // clang-format off // The statistic entries must be placed at the bottom or otherwise there will be problems with // saving the values in GuiMetaDataEd. MetaDataDecl gameDecls[] { // Key Type Default value Statistic Name in GuiMetaDataEd Prompt in GuiMetaDataEd Scrape {"name", MD_STRING, "", false, "NAME", "ENTER NAME", true}, {"sortname", MD_STRING, "", false, "SORTNAME", "ENTER SORTNAME", false}, {"collectionsortname", MD_STRING, "", false, "CUSTOM COLLECTIONS SORTNAME", "ENTER COLLECTIONS SORTNAME", false}, {"desc", MD_MULTILINE_STRING, "", false, "DESCRIPTION", "ENTER DESCRIPTION", true}, {"rating", MD_RATING, "0", false, "RATING", "ENTER RATING", true}, {"releasedate", MD_DATE, "19700101T000000", false, "RELEASE DATE", "ENTER RELEASE DATE", true}, {"developer", MD_STRING, "unknown", false, "DEVELOPER", "ENTER DEVELOPER", true}, {"publisher", MD_STRING, "unknown", false, "PUBLISHER", "ENTER PUBLISHER", true}, {"genre", MD_STRING, "unknown", false, "GENRE", "ENTER GENRE", true}, {"players", MD_STRING, "unknown", false, "PLAYERS", "ENTER NUMBER OF PLAYERS", true}, {"favorite", MD_BOOL, "false", false, "FAVORITE", "ENTER FAVORITE OFF/ON", false}, {"completed", MD_BOOL, "false", false, "COMPLETED", "ENTER COMPLETED OFF/ON", false}, {"kidgame", MD_BOOL, "false", false, "KIDGAME", "ENTER KIDGAME OFF/ON", false}, {"hidden", MD_BOOL, "false", false, "HIDDEN", "ENTER HIDDEN OFF/ON", false}, {"broken", MD_BOOL, "false", false, "BROKEN/NOT WORKING", "ENTER BROKEN OFF/ON", false}, {"nogamecount", MD_BOOL, "false", false, "EXCLUDE FROM GAME COUNTER", "ENTER DON'T COUNT AS GAME OFF/ON", false}, {"nomultiscrape", MD_BOOL, "false", false, "EXCLUDE FROM MULTI-SCRAPER", "ENTER NO MULTI-SCRAPE OFF/ON", false}, {"hidemetadata", MD_BOOL, "false", false, "HIDE METADATA FIELDS", "ENTER HIDE METADATA OFF/ON", false}, {"playcount", MD_INT, "0", false, "TIMES PLAYED", "ENTER NUMBER OF TIMES PLAYED", false}, {"controller", MD_CONTROLLER, "", false, "CONTROLLER", "SELECT CONTROLLER", true}, {"altemulator", MD_ALT_EMULATOR, "", false, "ALTERNATIVE EMULATOR", "SELECT ALTERNATIVE EMULATOR", false}, {"lastplayed", MD_TIME, "0", true, "LAST PLAYED", "ENTER LAST PLAYED DATE", false} }; MetaDataDecl folderDecls[] { // Key Type Default value Statistic Name in GuiMetaDataEd Prompt in GuiMetaDataEd Scrape {"name", MD_STRING, "", false, "NAME", "ENTER NAME", true}, {"desc", MD_MULTILINE_STRING, "", false, "DESCRIPTION", "ENTER DESCRIPTION", true}, {"rating", MD_RATING, "0", false, "RATING", "ENTER RATING", true}, {"releasedate", MD_DATE, "19700101T000000", false, "RELEASE DATE", "ENTER RELEASE DATE", true}, {"developer", MD_STRING, "unknown", false, "DEVELOPER", "ENTER DEVELOPER", true}, {"publisher", MD_STRING, "unknown", false, "PUBLISHER", "ENTER PUBLISHER", true}, {"genre", MD_STRING, "unknown", false, "GENRE", "ENTER GENRE", true}, {"players", MD_STRING, "unknown", false, "PLAYERS", "ENTER NUMBER OF PLAYERS", true}, {"favorite", MD_BOOL, "false", false, "FAVORITE", "ENTER FAVORITE OFF/ON", false}, {"completed", MD_BOOL, "false", false, "COMPLETED", "ENTER COMPLETED OFF/ON", false}, {"kidgame", MD_BOOL, "false", false, "KIDGAME (ONLY AFFECTS BADGES)", "ENTER KIDGAME OFF/ON", false}, {"hidden", MD_BOOL, "false", false, "HIDDEN", "ENTER HIDDEN OFF/ON", false}, {"broken", MD_BOOL, "false", false, "BROKEN/NOT WORKING", "ENTER BROKEN OFF/ON", false}, {"nomultiscrape", MD_BOOL, "false", false, "EXCLUDE FROM MULTI-SCRAPER", "ENTER NO MULTI-SCRAPE OFF/ON", false}, {"hidemetadata", MD_BOOL, "false", false, "HIDE METADATA FIELDS", "ENTER HIDE METADATA OFF/ON", false}, {"controller", MD_CONTROLLER, "", false, "CONTROLLER", "SELECT CONTROLLER", true}, {"folderlink", MD_FOLDER_LINK, "", false, "FOLDER LINK", "SELECT FOLDER LINK", false}, {"lastplayed", MD_TIME, "0", true, "LAST PLAYED", "ENTER LAST PLAYED DATE", false} }; // clang-format on const std::vector gameMDD {gameDecls, gameDecls + sizeof(gameDecls) / sizeof(gameDecls[0])}; const std::vector folderMDD { folderDecls, folderDecls + sizeof(folderDecls) / sizeof(folderDecls[0])}; } // namespace const std::vector& getMDDByType(MetaDataListType type) { switch (type) { case GAME_METADATA: return gameMDD; case FOLDER_METADATA: return folderMDD; } LOG(LogError) << "Invalid MDD type"; return gameMDD; } MetaDataList::MetaDataList(MetaDataListType type) : mType(type) , mWasChanged(false) { const std::vector& mdd = getMDD(); for (auto it = mdd.cbegin(); it != mdd.cend(); ++it) set(it->key, it->defaultValue); } MetaDataList MetaDataList::createFromXML(MetaDataListType type, pugi::xml_node& node, const std::string& relativeTo) { MetaDataList mdl(type); const std::vector& mdd = mdl.getMDD(); for (auto it = mdd.cbegin(); it != mdd.cend(); ++it) { pugi::xml_node md = node.child(it->key.c_str()); if (md && !md.text().empty()) { // If it's a path, resolve relative paths. std::string value = md.text().get(); if (it->type == MD_PATH) value = Utils::FileSystem::resolveRelativePath(value, relativeTo, true); mdl.set(it->key, value); } else { mdl.set(it->key, it->defaultValue); } } return mdl; } void MetaDataList::appendToXML(pugi::xml_node& parent, bool ignoreDefaults, const std::string& relativeTo) const { const std::vector& mdd = getMDD(); for (auto it = mdd.cbegin(); it != mdd.cend(); ++it) { auto mapIter = mMap.find(it->key); if (mapIter != mMap.cend()) { // We have this value! // If it's just the default (and we ignore defaults), don't write it. if (ignoreDefaults && mapIter->second == it->defaultValue) continue; // Try and make paths relative if we can. std::string value = mapIter->second; if (it->type == MD_PATH) value = Utils::FileSystem::createRelativePath(value, relativeTo, true); parent.append_child(mapIter->first.c_str()).text().set(value.c_str()); } } } void MetaDataList::set(const std::string& key, const std::string& value) { mMap[key] = value; mWasChanged = true; } const std::string& MetaDataList::get(const std::string& key) const { // Check that the key actually exists, otherwise return an empty string. if (mMap.count(key) > 0) return mMap.at(key); else return mNoResult; } int MetaDataList::getInt(const std::string& key) const { // Return integer value. return atoi(get(key).c_str()); } float MetaDataList::getFloat(const std::string& key) const { // Return float value. return static_cast(atof(get(key).c_str())); } bool MetaDataList::wasChanged() const { // Return whether the metadata was changed. return mWasChanged; } void MetaDataList::resetChangedFlag() { // Reset the change flag. mWasChanged = false; } #if defined(GETTEXT_DUMMY_ENTRIES) void gettextMessageCatalogEntries() { _p("metadata", "NAME"); _p("metadata", "ENTER NAME"); _p("metadata", "SORTNAME"); _p("metadata", "ENTER SORTNAME"); _p("metadata", "CUSTOM COLLECTIONS SORTNAME"); _p("metadata", "ENTER COLLECTIONS SORTNAME"); _p("metadata", "DESCRIPTION"); _p("metadata", "ENTER DESCRIPTION"); _p("metadata", "RATING"); _p("metadata", "RELEASE DATE"); _p("metadata", "DEVELOPER"); _p("metadata", "ENTER DEVELOPER"); _p("metadata", "PUBLISHER"); _p("metadata", "ENTER PUBLISHER"); _p("metadata", "GENRE"); _p("metadata", "ENTER GENRE"); _p("metadata", "PLAYERS"); _p("metadata", "ENTER NUMBER OF PLAYERS"); _p("metadata", "FAVORITE"); _p("metadata", "COMPLETED"); _p("metadata", "KIDGAME"); _p("metadata", "KIDGAME (ONLY AFFECTS BADGES)"); _p("metadata", "HIDDEN"); _p("metadata", "BROKEN/NOT WORKING"); _p("metadata", "EXCLUDE FROM GAME COUNTER"); _p("metadata", "EXCLUDE FROM MULTI-SCRAPER"); _p("metadata", "HIDE METADATA FIELDS"); _p("metadata", "TIMES PLAYED"); _p("metadata", "ENTER NUMBER OF TIMES PLAYED"); _p("metadata", "CONTROLLER"); _p("metadata", "SELECT CONTROLLER"); _p("metadata", "ALTERNATIVE EMULATOR"); _p("metadata", "SELECT ALTERNATIVE EMULATOR"); _p("metadata", "FOLDER LINK"); _p("metadata", "SELECT FOLDER LINK"); _p("metadata", "LAST PLAYED"); _p("metadata", "ENTER LAST PLAYED DATE"); } #endif