Added support for trurip SuperDAT files (to be placed in the meta/trurip

directory). Also added check for meta.db update based on file timestamps.
This commit is contained in:
Pieter Hulshoff 2017-01-11 10:54:02 +01:00
parent e8af81df71
commit 5956eec040
2 changed files with 211 additions and 3 deletions

View File

@ -33,6 +33,10 @@
#include <zlib.h>
#include <exception>
#if defined(__linux) || defined(__APPLE__)
#include <sys/stat.h>
#endif
MetadataDatabase::MetadataDatabase(DB &db, Configuration &c)
: config_(c)
, db_(db)
@ -115,8 +119,9 @@ bool MetadataDatabase::importDirectory()
{
DIR *dp;
struct dirent *dirp;
std::string hyperListPath = Utils::combinePath(Configuration::absolutePath, "meta", "hyperlist");
std::string mameListPath = Utils::combinePath(Configuration::absolutePath, "meta", "mamelist");
std::string hyperListPath = Utils::combinePath(Configuration::absolutePath, "meta", "hyperlist");
std::string mameListPath = Utils::combinePath(Configuration::absolutePath, "meta", "mamelist");
std::string truripListPath = Utils::combinePath(Configuration::absolutePath, "meta", "trurip");
dp = opendir(hyperListPath.c_str());
@ -183,6 +188,37 @@ bool MetadataDatabase::importDirectory()
closedir(dp);
}
dp = opendir(truripListPath.c_str());
if(dp == NULL)
{
Logger::write(Logger::ZONE_INFO, "MetadataDatabase", "Could not read directory \"" + truripListPath + "\"");
}
else
{
while((dirp = readdir(dp)) != NULL)
{
if (dirp->d_type != DT_DIR && std::string(dirp->d_name) != "." && std::string(dirp->d_name) != "..")
{
std::string basename = dirp->d_name;
std::string extension = basename.substr(basename.find_last_of("."), basename.size()-1);
basename = basename.substr(0, basename.find_last_of("."));
if(extension == ".dat")
{
std::string importFile = Utils::combinePath(truripListPath, std::string(dirp->d_name));
Logger::write(Logger::ZONE_INFO, "Metadata", "Importing truriplist: " + importFile);
importTruriplist(importFile);
}
}
}
closedir(dp);
}
return true;
}
@ -307,8 +343,11 @@ bool MetadataDatabase::needsRefresh()
if(rc == SQLITE_ROW)
{
int count = sqlite3_column_int(stmt, 0);
struct stat metadb;
int metadbErr = stat( Utils::combinePath(Configuration::absolutePath, "meta.db").c_str(), &metadb);
time_t metadirTime = timeDir(Utils::combinePath(Configuration::absolutePath, "meta"));
return (count == 0) ? true : false;
return (count == 0 || metadbErr || metadb.st_mtime < metadirTime) ? true : false;
}
else
{
@ -524,3 +563,170 @@ bool MetadataDatabase::importMamelist(std::string filename, std::string collecti
return true;
}
bool MetadataDatabase::importTruriplist(std::string truriplistFile)
{
char *error = NULL;
config_.setProperty("status", "Scraping data from \"" + truriplistFile + "\"");
rapidxml::xml_document<> doc;
std::ifstream file(truriplistFile.c_str());
std::vector<char> buffer((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
try
{
buffer.push_back('\0');
doc.parse<0>(&buffer[0]);
rapidxml::xml_node<> *root = doc.first_node("datafile");
if(!root)
{
Logger::write(Logger::ZONE_ERROR, "Metadata", "Does not appear to be a TruripList file (missing <datafile> tag)");
return false;
}
rapidxml::xml_node<> *header = root->first_node("header");
if (!header)
{
Logger::write(Logger::ZONE_ERROR, "Metadata", "Does not appear to be a TruripList file (missing <header> tag)");
return false;
}
rapidxml::xml_node<> *name = header->first_node("name");
if (!name)
{
Logger::write(Logger::ZONE_ERROR, "Metadata", "Does not appear to be a TruripList SuperDat file (missing <name> in <header> tag)");
return false;
}
std::string collectionName = name->value();
std::size_t pos = collectionName.find(" - ");
if(pos != std::string::npos)
{
collectionName = collectionName.substr(0, pos);
}
sqlite3 *handle = db_.handle;
sqlite3_exec(handle, "BEGIN IMMEDIATE TRANSACTION;", NULL, NULL, &error);
for(rapidxml::xml_node<> *game = root->first_node("game"); game; game = game->next_sibling("game"))
{
rapidxml::xml_node<> *descriptionXml = game->first_node("description");
rapidxml::xml_node<> *truripXml = game->first_node("trurip");
if (!truripXml)
{
Logger::write(Logger::ZONE_ERROR, "Metadata", "Does not appear to be a TruripList SuperDat file (missing <trurip> tag)");
return false;
}
rapidxml::xml_node<> *cloneofXml = truripXml->first_node("cloneof");
rapidxml::xml_node<> *manufacturerXml = truripXml->first_node("publisher");
rapidxml::xml_node<> *developerXml = truripXml->first_node("developer");
rapidxml::xml_node<> *yearXml = truripXml->first_node("year");
rapidxml::xml_node<> *genreXml = truripXml->first_node("genre");
rapidxml::xml_node<> *ratingXml = truripXml->first_node("ratings");
rapidxml::xml_node<> *scoreXml = truripXml->first_node("score");
rapidxml::xml_node<> *numberPlayersXml = truripXml->first_node("players");
rapidxml::xml_node<> *enabledXml = truripXml->first_node("enabled");
std::string name = (descriptionXml) ? descriptionXml->value() : "";
std::string description = (descriptionXml) ? descriptionXml->value() : "";
std::string crc = "";
std::string cloneOf = (cloneofXml) ? cloneofXml->value() : "";
std::string manufacturer = (manufacturerXml) ? manufacturerXml->value() : "";
std::string developer = (developerXml) ? developerXml->value() : "";
std::string year = (yearXml) ? yearXml->value() : "";
std::string genre = (genreXml) ? genreXml->value() : "";
std::string rating = (ratingXml) ? ratingXml->value() : "";
std::string score = (scoreXml) ? scoreXml->value() : "";
std::string numberPlayers = (numberPlayersXml) ? numberPlayersXml->value() : "";
std::string ctrlType = "";
std::string numberButtons = "";
std::string numberJoyWays = "";
std::string enabled = (enabledXml) ? enabledXml->value() : "";
if(name.length() > 0)
{
sqlite3_stmt *stmt;
sqlite3_prepare_v2(handle,
"INSERT OR REPLACE INTO Meta (name, title, year, manufacturer, developer, genre, players, ctrltype, buttons, joyways, cloneOf, collectionName, rating, score) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
-1, &stmt, 0);
sqlite3_bind_text(stmt, 1, name.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 2, description.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 3, year.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 4, manufacturer.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 5, developer.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 6, genre.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 7, numberPlayers.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 8, ctrlType.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 9, numberButtons.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 10, numberJoyWays.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 11, cloneOf.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 12, collectionName.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 13, rating.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 14, score.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_step(stmt);
sqlite3_finalize(stmt);
}
}
config_.setProperty("status", "Saving data from \"" + truriplistFile + "\" to database");
sqlite3_exec(handle, "COMMIT TRANSACTION;", NULL, NULL, &error);
return true;
}
catch(rapidxml::parse_error &e)
{
std::string what = e.what();
long line = static_cast<long>(std::count(&buffer.front(), e.where<char>(), char('\n')) + 1);
std::stringstream ss;
ss << "Could not parse layout file. [Line: " << line << "] Reason: " << e.what();
Logger::write(Logger::ZONE_ERROR, "Metadata", ss.str());
}
catch(std::exception &e)
{
std::string what = e.what();
Logger::write(Logger::ZONE_ERROR, "Metadata", "Could not parse truriplist file. Reason: " + what);
}
return false;
}
time_t MetadataDatabase::timeDir( std::string path )
{
time_t lastTime = 0;
DIR *dp;
struct dirent *dirp;
dp = opendir( path.c_str( ) );
while (dp != NULL && (dirp = readdir( dp )) != NULL)
{
std::string file = dirp->d_name;
// Check if file is a directory
struct stat sb;
if (file != "." && file != ".." && stat( Utils::combinePath( path, file ).c_str( ), &sb ) == 0 && S_ISDIR( sb.st_mode ))
{
time_t tmpTime = timeDir( Utils::combinePath( path, file ) );
lastTime = (tmpTime > lastTime) ? tmpTime : lastTime;
}
else if (file != "." && file != "..")
{
struct stat filestat;
int err = stat( Utils::combinePath( path, file ).c_str( ), &filestat );
lastTime = (!err && filestat.st_mtime > lastTime) ? filestat.st_mtime : lastTime;
}
}
if (dp != NULL)
{
closedir( dp );
}
return lastTime;
}

View File

@ -35,10 +35,12 @@ public:
void injectMetadata(CollectionInfo *collection);
bool importHyperlist(std::string hyperlistFile, std::string collectionName);
bool importMamelist(std::string filename, std::string collectionName);
bool importTruriplist(std::string filename);
private:
bool importDirectory();
bool needsRefresh();
time_t timeDir(std::string path);
Configuration &config_;
DB &db_;
};