Commit 6c54fad7 authored by Bkg2k's avatar Bkg2k

Moved from old to new Metadata management

parent 4a55e973
......@@ -4,7 +4,6 @@ set(ES_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/src/EmulationStation.h
${CMAKE_CURRENT_SOURCE_DIR}/src/FileData.h
${CMAKE_CURRENT_SOURCE_DIR}/src/FileSorts.h
${CMAKE_CURRENT_SOURCE_DIR}/src/MetaData.h
${CMAKE_CURRENT_SOURCE_DIR}/src/MetadataDescriptor.h
${CMAKE_CURRENT_SOURCE_DIR}/src/MetadataFieldDescriptor.h
${CMAKE_CURRENT_SOURCE_DIR}/src/PlatformId.h
......@@ -66,7 +65,6 @@ set(ES_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/FileSorts.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/MameNameMap.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/MetaData.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/MetadataDescriptor.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/MetadataFieldDescriptor.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/PlatformId.cpp
......
......@@ -49,12 +49,8 @@ std::string removeParenthesis(const std::string& str)
FileData::FileData(FileType type, const fs::path& path, SystemData* system)
: mType(type), mPath(path), mSystem(system), mParent(NULL), metadata(type == GAME ? GAME_METADATA : FOLDER_METADATA) // metadata is REALLY set in the constructor!
: mType(type), mPath(path), mSystem(system), mParent(NULL), metadata(getCleanName()) // TODO: Find a better way to move the default name into metadata
{
// metadata needs at least a name field (since that's what getName() will return)
if(metadata.get("name").empty())
metadata.set("name", getCleanName());
metadata.set("system", system->getName());
}
FileData::~FileData()
......@@ -71,15 +67,13 @@ std::string FileData::getCleanName() const
if(mSystem && (mSystem->hasPlatformId(PlatformIds::ARCADE) || mSystem->hasPlatformId(PlatformIds::NEOGEO)))
stem = PlatformIds::getCleanMameName(stem.c_str());
return stem;
//return removeParenthesis(stem);
return removeParenthesis(stem);
}
const std::string& FileData::getThumbnailPath() const
{
if(!metadata.get("thumbnail").empty())
return metadata.get("thumbnail");
else
return metadata.get("image");
return (!metadata.Thumbnail().empty()) ? metadata.Thumbnail() : metadata.Image();
}
......@@ -109,7 +103,7 @@ std::vector<FileData*> FileData::getFavoritesRecursive(unsigned int typeMask) co
for (auto it = files.begin(); it != files.end(); it++)
{
if ((*it)->metadata.get("favorite").compare("true") == 0)
if ((*it)->metadata.Favorite())
{
out.push_back(*it);
}
......@@ -125,7 +119,7 @@ std::vector<FileData*> FileData::getHiddenRecursive(unsigned int typeMask) const
for (auto it = files.begin(); it != files.end(); it++)
{
if ((*it)->metadata.get("hidden").compare("true") == 0)
if ((*it)->metadata.Hidden())
{
out.push_back(*it);
}
......@@ -261,12 +255,15 @@ void FileData::populateRecursiveFolder(FileData* folder, const std::vector<std::
}
}
std::vector<FileData *> FileData::getDisplayableRecursive(unsigned int typeMask) const {
std::vector<FileData *> FileData::getDisplayableRecursive(unsigned int typeMask) const
{
std::vector<FileData *> out;
std::vector<FileData *> files = getFilesRecursive(typeMask);
for (auto it = files.begin(); it != files.end(); it++) {
if ((*it)->metadata.get("hidden").compare("true") != 0) {
for (auto it = files.begin(); it != files.end(); it++)
{
if (!(*it)->metadata.Hidden())
{
out.push_back(*it);
}
}
......@@ -274,7 +271,8 @@ std::vector<FileData *> FileData::getDisplayableRecursive(unsigned int typeMask)
return out;
}
bool FileData::isSingleGameFolder() const {
bool FileData::isSingleGameFolder() const
{
assert(mType == FOLDER);
return (mChildren.size() == 1) && (mChildren.at(0)->getType() == GAME);
}
\ No newline at end of file
......@@ -4,7 +4,8 @@
#include <unordered_map>
#include <string>
#include <boost/filesystem.hpp>
#include "MetaData.h"
#include <components/IList.h>
#include "MetadataDescriptor.h"
class SystemData;
......@@ -39,8 +40,8 @@ public:
FileData(FileType type, const boost::filesystem::path& path, SystemData* system);
virtual ~FileData();
inline const std::string& getName() const { return metadata.get("name"); }
inline const std::string& getHash() const { return metadata.get("hash"); }
inline const std::string& getName() const { return metadata.Name(); }
inline const std::string getHash() const { return std::move(metadata.RomCrc32AsString()); }
inline FileType getType() const { return mType; }
inline const boost::filesystem::path& getPath() const { return mPath; }
inline FileData* getParent() const { return mParent; }
......@@ -67,19 +68,18 @@ public:
bool isSingleGameFolder() const;
typedef bool ComparisonFunction(const FileData* a, const FileData* b);
struct SortType
{
ComparisonFunction* comparisonFunction;
bool ascending;
std::string description;
SortType(ComparisonFunction* sortFunction, bool sortAscending, const std::string & sortDescription)
: comparisonFunction(sortFunction), ascending(sortAscending), description(sortDescription) {}
};
static void populateRecursiveFolder(FileData* folder, const std::vector<std::string>& searchExtensions = std::vector<std::string>(), SystemData* systemData = nullptr);
MetaDataList metadata;
/*!
* const Metadata accessor for Read operations
* @return const Metadata object
*/
const MetadataDescriptor& Metadata() const { return metadata; }
/*!
* Metadata accessor for Write operations only
* @return Writable Metadata object
*/
MetadataDescriptor& Metadata() { return metadata; }
private:
FileType mType;
......@@ -88,4 +88,6 @@ private:
FileData* mParent;
std::unordered_map<std::string,FileData*> mChildrenByFilename;
std::vector<FileData*> mChildren;
MetadataDescriptor metadata;
};
......@@ -3,130 +3,113 @@
namespace FileSorts
{
std::vector<FileData::SortType> SortTypes;
std::vector<SortType> SortTypes;
void init() {
SortTypes.push_back(FileData::SortType(&compareFileName, true, "\uF15d " + _("FILENAME")));
SortTypes.push_back(FileData::SortType(&compareFileName, false, "\uF15e " + _("FILENAME")));
SortTypes.push_back(FileData::SortType(&compareRating, true, "\uF165 " + _("RATING")));
SortTypes.push_back(FileData::SortType(&compareRating, false, "\uF164 " + _("RATING")));
SortTypes.push_back(FileData::SortType(&compareTimesPlayed, true, "\uF160 " + _("TIMES PLAYED")));
SortTypes.push_back(FileData::SortType(&compareTimesPlayed, false, "\uF161 " + _("TIMES PLAYED")));
SortTypes.push_back(FileData::SortType(&compareLastPlayed, true, "\uF160 " + _("LAST PLAYED")));
SortTypes.push_back(FileData::SortType(&compareLastPlayed, false, "\uF161 " + _("LAST PLAYED")));
SortTypes.push_back(FileData::SortType(&compareNumberPlayers, true, "\uF162 " + _("NUMBER OF PLAYERS")));
SortTypes.push_back(FileData::SortType(&compareNumberPlayers, false, "\uF163 " + _("NUMBER OF PLAYERS")));
SortTypes.push_back(FileData::SortType(&compareDevelopper, true, "\uF15d " + _("DEVELOPER")));
SortTypes.push_back(FileData::SortType(&compareDevelopper, false, "\uF15e " + _("DEVELOPER")));
SortTypes.push_back(FileData::SortType(&compareGenre, true, "\uF15d " + _("GENRE")));
SortTypes.push_back(FileData::SortType(&compareGenre, false, "\uF15e " + _("GENRE")));
SortTypes.push_back(SortType(&compareFileName, true, "\uF15d " + _("FILENAME")));
SortTypes.push_back(SortType(&compareFileName, false, "\uF15e " + _("FILENAME")));
SortTypes.push_back(SortType(&compareRating, true, "\uF165 " + _("RATING")));
SortTypes.push_back(SortType(&compareRating, false, "\uF164 " + _("RATING")));
SortTypes.push_back(SortType(&compareTimesPlayed, true, "\uF160 " + _("TIMES PLAYED")));
SortTypes.push_back(SortType(&compareTimesPlayed, false, "\uF161 " + _("TIMES PLAYED")));
SortTypes.push_back(SortType(&compareLastPlayed, true, "\uF160 " + _("LAST PLAYED")));
SortTypes.push_back(SortType(&compareLastPlayed, false, "\uF161 " + _("LAST PLAYED")));
SortTypes.push_back(SortType(&compareNumberPlayers, true, "\uF162 " + _("NUMBER OF PLAYERS")));
SortTypes.push_back(SortType(&compareNumberPlayers, false, "\uF163 " + _("NUMBER OF PLAYERS")));
SortTypes.push_back(SortType(&compareDevelopper, true, "\uF15d " + _("DEVELOPER")));
SortTypes.push_back(SortType(&compareDevelopper, false, "\uF15e " + _("DEVELOPER")));
SortTypes.push_back(SortType(&compareGenre, true, "\uF15d " + _("GENRE")));
SortTypes.push_back(SortType(&compareGenre, false, "\uF15e " + _("GENRE")));
}
//returns if file1 should come before file2
bool compareFileName(const FileData* file1, const FileData* file2)
static int SimpleCompareUppercase(const std::string& a, const std::string& b)
{
std::string name1 = file1->getName();
std::string name2 = file2->getName();
//min of name1/name2 .length()s
unsigned int count = name1.length() > name2.length() ? name2.length() : name1.length();
for(unsigned int i = 0; i < count; i++)
for(const char *ap = a.c_str(), *bp = b.c_str();; ap++, bp++)
{
if(toupper(name1[i]) != toupper(name2[i]))
{
return toupper(name1[i]) < toupper(name2[i]);
}
int c1 = std::toupper(*ap);
int c2 = std::toupper(*bp);
if ((c1 | c2) == 0) return 0;
int c = c1 - c2;
if (c != 0) return c;
}
}
return name1.length() < name2.length();
//returns if file1 should come before file2
ImplementSortMethod(compareFileName)
{
return SimpleCompareUppercase(file1->getName(), file2->getName());
}
bool compareRating(const FileData* file1, const FileData* file2)
ImplementSortMethod(compareRating)
{
//only games have rating metadata
if(file1->metadata.getType() == GAME_METADATA && file2->metadata.getType() == GAME_METADATA)
if (MetadataDescriptor::AreGames(file1->Metadata(), file2->Metadata()))
{
return file1->metadata.getFloat("rating") < file2->metadata.getFloat("rating");
float c = file1->Metadata().Rating() - file2->Metadata().Rating();
if (c < 0) return - 1;
if (c > 0) return 1;
return 0;
}
return false;
return 0;
}
bool compareTimesPlayed(const FileData* file1, const FileData* file2)
ImplementSortMethod(compareTimesPlayed)
{
//only games have playcount metadata
if(file1->metadata.getType() == GAME_METADATA && file2->metadata.getType() == GAME_METADATA)
if (MetadataDescriptor::AreGames(file1->Metadata(), file2->Metadata()))
{
return (file1)->metadata.getInt("playcount") < (file2)->metadata.getInt("playcount");
return (file1)->Metadata().PlayCount() - (file2)->Metadata().PlayCount();
}
return false;
return 0;
}
bool compareLastPlayed(const FileData* file1, const FileData* file2)
ImplementSortMethod(compareLastPlayed)
{
//only games have lastplayed metadata
if(file1->metadata.getType() == GAME_METADATA && file2->metadata.getType() == GAME_METADATA)
if (MetadataDescriptor::AreGames(file1->Metadata(), file2->Metadata()))
{
return (file1)->metadata.getTime("lastplayed") < (file2)->metadata.getTime("lastplayed");
TimeSpan ts = (file1)->Metadata().LastPlayed() - (file2)->Metadata().LastPlayed();
if (ts.IsNull()) return 0;
if (ts.IsNegative()) return -1;
return 1;
}
return false;
return 0;
}
bool compareNumberPlayers(const FileData* file1, const FileData* file2)
ImplementSortMethod(compareNumberPlayers)
{
//only games have lastplayed metadata
if(file1->metadata.getType() == GAME_METADATA && file2->metadata.getType() == GAME_METADATA)
if (MetadataDescriptor::AreGames(file1->Metadata(), file2->Metadata()))
{
return (file1)->metadata.getInt("players") < (file2)->metadata.getInt("players");
return (file1)->Metadata().PlayerRange() - (file2)->Metadata().PlayerRange();
}
return false;
return 0;
}
bool compareDevelopper(const FileData* file1, const FileData* file2)
ImplementSortMethod(compareDevelopper)
{
//only games have developper metadata
if(file1->metadata.getType() == GAME_METADATA && file2->metadata.getType() == GAME_METADATA)
if (MetadataDescriptor::AreGames(file1->Metadata(), file2->Metadata()))
{
std::string dev1 = file1->metadata.get("developer");
std::string dev2 = file2->metadata.get("developer");
//min of dev1/dev2 .length()s
unsigned int count = dev1.length() > dev2.length() ? dev2.length() : dev1.length();
for(unsigned int i = 0; i < count; i++)
{
if(toupper(dev1[i]) != toupper(dev2[i]))
{
return toupper(dev1[i]) < toupper(dev2[i]);
}
}
return SimpleCompareUppercase(file1->Metadata().Developer(), file2->Metadata().Developer());
}
return false;
return 0;
}
bool compareGenre(const FileData* file1, const FileData* file2)
ImplementSortMethod(compareGenre)
{
//only games have genre metadata
if(file1->metadata.getType() == GAME_METADATA && file2->metadata.getType() == GAME_METADATA)
if (MetadataDescriptor::AreGames(file1->Metadata(), file2->Metadata()))
{
std::string genre1 = file1->metadata.get("genre");
std::string genre2 = file2->metadata.get("genre");
//min of genre1/genre2 .length()s
unsigned int count = genre1.length() > genre2.length() ? genre2.length() : genre1.length();
for(unsigned int i = 0; i < count; i++)
{
if(toupper(genre1[i]) != toupper(genre2[i]))
{
return toupper(genre1[i]) < toupper(genre2[i]);
}
}
return SimpleCompareUppercase(file1->Metadata().Genre(), file2->Metadata().Genre());
}
return false;
return 0;
}
};
......@@ -5,14 +5,27 @@
namespace FileSorts
{
bool compareFileName(const FileData* file1, const FileData* file2);
bool compareRating(const FileData* file1, const FileData* file2);
bool compareTimesPlayed(const FileData* file1, const FileData* fil2);
bool compareLastPlayed(const FileData* file1, const FileData* file2);
bool compareNumberPlayers(const FileData* file1, const FileData* file2);
bool compareDevelopper(const FileData* file1, const FileData* file2);
bool compareGenre(const FileData* file1, const FileData* file2);
struct SortType
{
int (*comparisonFunction)(FileData* const a, FileData* const b);
bool ascending;
std::string description;
extern std::vector<FileData::SortType> SortTypes;
SortType(int (*sortFunction)(FileData* const a, FileData* const b), bool sortAscending, const std::string & sortDescription)
: comparisonFunction(sortFunction), ascending(sortAscending), description(sortDescription) {}
};
#define DeclareSortMethodPrototype(x) int x(FileData* const file1, FileData* const file2);
#define ImplementSortMethod(x) int x(FileData* const file1, FileData* const file2)
DeclareSortMethodPrototype(compareFileName)
DeclareSortMethodPrototype(compareRating)
DeclareSortMethodPrototype(compareTimesPlayed)
DeclareSortMethodPrototype(compareLastPlayed)
DeclareSortMethodPrototype(compareNumberPlayers)
DeclareSortMethodPrototype(compareDevelopper)
DeclareSortMethodPrototype(compareGenre)
extern std::vector<SortType> SortTypes;
void init();
};
#include "Gamelist.h"
#include "SystemData.h"
#include "pugixml/pugixml.hpp"
#include <boost/filesystem.hpp>
#include <boost/property_tree/xml_parser.hpp>
#include <RecalboxConf.h>
#include "Log.h"
#include "Settings.h"
......@@ -9,6 +9,7 @@
#include "recalbox/RecalboxSystem.h"
namespace fs = boost::filesystem;
namespace pt = boost::property_tree;
FileData* findOrCreateFile(SystemData* system, const boost::filesystem::path& path, FileType type, bool trustGamelist)
{
......@@ -28,18 +29,17 @@ FileData* findOrCreateFile(SystemData* system, const boost::filesystem::path& pa
if(!contains)
{
LOG(LogError) << "File path \"" << path << "\" is outside system path \"" << system->getStartPath() << "\"";
return NULL;
return nullptr;
}
auto path_it = relative.begin();
FileData* treeNode = root;
bool found = false;
while(path_it != relative.end())
{
const std::unordered_map<std::string, FileData*>& children = treeNode->getChildrenByFilename();
std::string key = path_it->string();
found = children.find(key) != children.end();
bool found = children.find(key) != children.end();
if (found) {
treeNode = children.at(key);
}
......@@ -53,7 +53,7 @@ FileData* findOrCreateFile(SystemData* system, const boost::filesystem::path& pa
if(type == FOLDER)
{
LOG(LogWarning) << "gameList: folder doesn't already exist, won't create";
return NULL;
return nullptr;
}
FileData* file = new FileData(type, path, system);
......@@ -68,7 +68,7 @@ FileData* findOrCreateFile(SystemData* system, const boost::filesystem::path& pa
if(type == FOLDER)
{
LOG(LogWarning) << "gameList: folder doesn't already exist, won't create";
return NULL;
return nullptr;
}
// create missing folder
......@@ -80,10 +80,61 @@ FileData* findOrCreateFile(SystemData* system, const boost::filesystem::path& pa
path_it++;
}
return NULL;
return nullptr;
}
void parseGamelist(SystemData* system)
{
bool trustGamelist = RecalboxConf::getInstance()->get("emulationstation.gamelistonly") == "1";
std::string xmlpath = system->getGamelistPath(false);
if(!boost::filesystem::exists(xmlpath))
return;
LOG(LogInfo) << "Parsing XML file \"" << xmlpath << "\"...";
MetadataDescriptor::Tree gameList;
try
{
pt::read_xml(xmlpath, gameList, 0, std::locale("en_US.UTF8"));
}
catch(std::exception& e)
{
LOG(LogError) << "Could not parse " << xmlpath <<" file!";
LOG(LogError) << e.what();
return;
}
fs::path relativeTo = system->getStartPath();
for (const auto& fileNode : gameList.get_child("gameList"))
{
FileType type;
if (fileNode.first == "game") type = FileType::GAME;
else if (fileNode.first == "folder") type = FileType::FOLDER;
else continue; // Unknown node
const MetadataDescriptor::Tree& children = fileNode.second;
fs::path path = resolvePath(children.get("path", ""), relativeTo, false);
if(!trustGamelist && !boost::filesystem::exists(path))
{
LOG(LogWarning) << "File \"" << path << "\" does not exist! Ignoring.";
continue;
}
FileData* file = findOrCreateFile(system, path, type, trustGamelist);
if(!file)
{
LOG(LogError) << "Error finding/creating FileData for \"" << path << "\", skipping.";
continue;
}
//load the metadata
file->Metadata().Deserialize(fileNode, relativeTo.generic_string());
}
}
/*void parseGamelist(SystemData* system)
{
bool trustGamelist = RecalboxConf::getInstance()->get("emulationstation.gamelistonly") == "1";
std::string xmlpath = system->getGamelistPath(false);
......@@ -135,7 +186,7 @@ void parseGamelist(SystemData* system)
}
//load the metadata
std::string defaultName = file->metadata.get("name");
std::string& defaultName = file->metadata.Name();
file->metadata = MetaDataList::createFromXML(GAME_METADATA, fileNode, relativeTo);
//make sure name gets set if one didn't exist
......@@ -146,9 +197,9 @@ void parseGamelist(SystemData* system)
file->metadata.resetChangedFlag();
}
}
}
}*/
void addFileDataNode(pugi::xml_node& parent, const FileData* file, const char* tag, SystemData* system)
/*void addFileDataNode(pugi::xml_node& parent, const FileData* file, const char* tag, SystemData* system)
{
//create game and add to parent node
pugi::xml_node newNode = parent.append_child(tag);
......@@ -169,9 +220,103 @@ void addFileDataNode(pugi::xml_node& parent, const FileData* file, const char* t
// try and make the path relative if we can so things still work if we change the rom folder location in the future
newNode.prepend_child("path").text().set(makeRelativePath(file->getPath(), system->getStartPath(), false).generic_string().c_str());
}
}
}*/
void updateGamelist(SystemData* system)
{
//We do this by reading the XML again, adding changes and then writing it back,
//because there might be information missing in our systemdata which would then miss in the new XML.
//We have the complete information for every game though, so we can simply remove a game
//we already have in the system from the XML, and then add it back from its GameData information...
if(Settings::getInstance()->getBool("IgnoreGamelist")) return;
try
{
/*
* Get all folder & games in a flat storage
*/
FileData *rootFolder = system->getRootFolder();
if (rootFolder == nullptr) return;
std::vector<FileData *> fileData = rootFolder->getFilesRecursive(GAME | FOLDER);
// Nothing to process?
if (fileData.size() == 0) return;
/*
* Create game/folder map for fast seeking using relative path as key
*/
std::unordered_map<std::string, const FileData *> fileLinks;
for (const FileData *file : fileData) // For each File
if (file->Metadata().IsDirty()) // with updated metadata
fileLinks[makeRelativePath(file->getPath(), system->getStartPath(), false).generic_string()] = file; // store the relative path
// Nothing changed?
if (fileLinks.empty()) return;
/*
* Load or create gamelist node
*/
std::string xmlReadPath = system->getGamelistPath(false);
MetadataDescriptor::Tree document;
if (boost::filesystem::exists(xmlReadPath))
{
try
{
pt::read_xml(xmlReadPath, document, 0, std::locale("en_US.UTF8"));
}
catch (std::exception &e)
{
LOG(LogError) << "Could not parse " << xmlReadPath << " file!";
LOG(LogError) << e.what();
}
} else
{
// Create empty game list node
document.add_child("gameList", MetadataDescriptor::Tree());
}
MetadataDescriptor::Tree &gameList = document.get_child("gameList");
/*
* Update pass #1 : Remove node from the gamelist where corresponding metadata have changed
*/
for (auto it = gameList.begin(); it != gameList.end();) // For each gamelist entry
if (fileLinks.find((*it).second.get("path", "")) != fileLinks.end()) // corresponding to an updated file
it = gameList.erase(it); // delete the entry from the gamelist
else
++it;
/*
* Update pass #2 - Insert new/updated game/folder nodes into the gamelist node
*/
for (const FileData *file : fileData) // For each file
if (file->Metadata().IsDirty()) // If metadata have changed
file->Metadata().Serialize(gameList, // Insert updated node
file->getPath().generic_string(),
system->getStartPath());
/*
* Write the list.
* At this point, we're sure at least one node has been updated (or added and updated).
*/
boost::filesystem::path xmlWritePath(system->getGamelistPath(true) + ".xml");
boost::filesystem::create_directories(xmlWritePath.parent_path());
try
{
pt::write_xml(xmlWritePath.generic_string(), document, std::locale("en_US.UTF8"));
LOG(LogInfo) << "Saved gamelist.xml for system " << system->getFullName() << ". Updated items: " << fileLinks.size() << "/" << fileData.size();
}
catch (std::exception &e)
{
LOG(LogError) << "Failed to save " << xmlWritePath.generic_string() << " : " << e.what();
}
}
catch(std::exception& e)
{
LOG(LogError) << "Something went wrong while saving " << system->getFullName() << " : " << e.what();
}
}
/*void updateGamelist(SystemData* system)
{
//We do this by reading the XML again, adding changes and then writing it back,
//because there might be information missing in our systemdata which would then miss in the new XML.
......@@ -272,4 +417,4 @@ void updateGamelist(SystemData* system)
}else{
LOG(LogError) << "Found no root folder for system \"" << system->getName() << "\"!";
}
}
}*/
#include "MetaData.h"
#include "components/TextComponent.h"
#include "Log.h"
#include "Util.h"
#include <strings.h>
#include "Locale.h"
namespace fs = boost::filesystem;
std::vector<MetaDataDecl> gameMDD;
std::vector<MetaDataDecl> folderMDD;
void initMetadata() {
gameMDD.push_back(MetaDataDecl("name", MD_STRING, "", false, true, _("Name"), _("enter game name")));
gameMDD.push_back(MetaDataDecl("hash", MD_STRING, "", true, false, _("hash"), _("enter game hash")));
gameMDD.push_back(MetaDataDecl("rating", MD_RATING, "0.000000", false, true, _("Rating"), _("enter rating")));
gameMDD.push_back(MetaDataDecl("favorite", MD_BOOL, "false", false, true, _("Favorite"), _("enter favorite")));
gameMDD.push_back(MetaDataDecl("hidden", MD_BOOL, "false", false, true, _("Hidden"), _("set hidden")));
gameMDD.push_back(MetaDataDecl("emulator", MD_LIST, "default", false, true, _("Emulator"), _("enter emulator")));
gameMDD.push_back(MetaDataDecl("core", MD_LIST, "default", false, true, _("Core"), _("enter core")));
gameMDD.push_back(MetaDataDecl("ratio", MD_LIST, "auto", false, true, _("Ratio"), _("enter ratio")));
gameMDD.push_back(MetaDataDecl("desc", MD_MULTILINE_STRING, "", false, false, _("Description"), _("enter description")));
gameMDD.push_back(MetaDataDecl("image", MD_IMAGE_PATH, "", false, false, _("Image"), _("enter path to image")));
gameMDD.push_back(MetaDataDecl("thumbnail", MD_IMAGE_PATH, "", false, false, _("Thumbnail"), _("enter path to thumbnail")));
gameMDD.push_back(MetaDataDecl("releasedate", MD_DATE, "not-a-date-time", false, false, _("Release date"), _("enter release date")));
gameMDD.push_back(MetaDataDecl("developer", MD_STRING, "unknown", false, false, _("Developer"), _("enter game developer")));
gameMDD.push_back(MetaDataDecl("publisher", MD_STRING, "unknown", false, false, _("Publisher"), _("enter game publisher")));
gameMDD.push_back(MetaDataDecl("genre", MD_STRING, "unknown", false, false, _("Genre"), _("enter game genre")));
gameMDD.push_back(MetaDataDecl("players", MD_INT, "1", false, false, _("Players"), _("enter number of players")));
gameMDD.push_back(MetaDataDecl("region", MD_STRING, "", false, false, _("Region"), _("enter region")));
gameMDD.push_back(MetaDataDecl("romtype", MD_STRING, "Original", false, false, _("Romtype"), _("enter romtype")));
gameMDD.push_back(MetaDataDecl("playcount", MD_INT, "0", true, false, _("Play count"), _("enter number of times played")));
gameMDD.push_back(MetaDataDecl("lastplayed", MD_TIME, "0", true, false, _("Last played"), _("enter last played date")));
folderMDD.push_back(MetaDataDecl("name", MD_STRING, "", false));
folderMDD.push_back(MetaDataDecl("desc", MD_MULTILINE_STRING, "", false));
folderMDD.push_back(MetaDataDecl("image", MD_IMAGE_PATH, "", false));
folderMDD.push_back(MetaDataDecl("thumbnail", MD_IMAGE_PATH, "", false));
folderMDD.push_back(MetaDataDecl("hidden", MD_BOOL, "false", false));
}
const std::vector<MetaDataDecl>& 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)
{
co