mirror of
https://github.com/FunKey-Project/RetroFE.git
synced 2026-06-02 17:06:48 +02:00
Support ability to import hyperlist
This commit is contained in:
@@ -25,9 +25,9 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
CollectionInfoBuilder::CollectionInfoBuilder(Configuration &c, DB &db)
|
CollectionInfoBuilder::CollectionInfoBuilder(Configuration &c, MetadataDatabase &mdb)
|
||||||
: Conf(c)
|
: Conf(c)
|
||||||
, MetaDB(db, c)
|
, MetaDB(mdb)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ CollectionInfo *CollectionInfoBuilder::BuildCollection(std::string name)
|
|||||||
std::string listItemsPath;
|
std::string listItemsPath;
|
||||||
std::string launcherName;
|
std::string launcherName;
|
||||||
std::string extensions;
|
std::string extensions;
|
||||||
std::string metadataType;
|
std::string metadataType = name;
|
||||||
std::string metadataPath;
|
std::string metadataPath;
|
||||||
|
|
||||||
Conf.GetCollectionAbsolutePath(name, listItemsPath);
|
Conf.GetCollectionAbsolutePath(name, listItemsPath);
|
||||||
@@ -137,7 +137,7 @@ bool CollectionInfoBuilder::ImportDirectory(CollectionInfo *info)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MetaDB.UpdateMetadata(info);
|
MetaDB.InjectMetadata(info);
|
||||||
|
|
||||||
while(includeFilter.size() > 0)
|
while(includeFilter.size() > 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../Database/DB.h"
|
|
||||||
#include "../Database/MetadataDatabase.h"
|
#include "../Database/MetadataDatabase.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
@@ -16,12 +15,12 @@ class CollectionInfo;
|
|||||||
class CollectionInfoBuilder
|
class CollectionInfoBuilder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CollectionInfoBuilder(Configuration &c, DB &db);
|
CollectionInfoBuilder(Configuration &c, MetadataDatabase &mdb);
|
||||||
virtual ~CollectionInfoBuilder();
|
virtual ~CollectionInfoBuilder();
|
||||||
CollectionInfo *BuildCollection(std::string collectionName);
|
CollectionInfo *BuildCollection(std::string collectionName);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MetadataDatabase MetaDB;
|
MetadataDatabase &MetaDB;
|
||||||
bool ImportDirectory(CollectionInfo *info);
|
bool ImportDirectory(CollectionInfo *info);
|
||||||
Configuration &Conf;
|
Configuration &Conf;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -47,12 +47,11 @@ MetadataDatabase::~MetadataDatabase()
|
|||||||
|
|
||||||
bool MetadataDatabase::ResetDatabase()
|
bool MetadataDatabase::ResetDatabase()
|
||||||
{
|
{
|
||||||
bool retVal = true;
|
|
||||||
int rc;
|
int rc;
|
||||||
char *error = NULL;
|
char *error = NULL;
|
||||||
sqlite3 *handle = DBInstance.GetHandle();
|
sqlite3 *handle = DBInstance.GetHandle();
|
||||||
|
|
||||||
Logger::Write(Logger::ZONE_INFO, "Database", "Erasing");
|
Logger::Write(Logger::ZONE_INFO, "Metadata", "Erasing");
|
||||||
|
|
||||||
std::string sql;
|
std::string sql;
|
||||||
sql.append("DROP TABLE IF EXISTS Meta;");
|
sql.append("DROP TABLE IF EXISTS Meta;");
|
||||||
@@ -63,11 +62,11 @@ bool MetadataDatabase::ResetDatabase()
|
|||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "Unable to create Metadata table. Error: " << error;
|
ss << "Unable to create Metadata table. Error: " << error;
|
||||||
Logger::Write(Logger::ZONE_ERROR, "Database", ss.str());
|
Logger::Write(Logger::ZONE_ERROR, "Metadata", ss.str());
|
||||||
retVal = false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return retVal;
|
return Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MetadataDatabase::Initialize()
|
bool MetadataDatabase::Initialize()
|
||||||
@@ -94,15 +93,61 @@ bool MetadataDatabase::Initialize()
|
|||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "Unable to create Metadata table. Error: " << error;
|
ss << "Unable to create Metadata table. Error: " << error;
|
||||||
Logger::Write(Logger::ZONE_ERROR, "Database", ss.str());
|
Logger::Write(Logger::ZONE_ERROR, "Metadata", ss.str());
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(NeedsRefresh())
|
||||||
|
{
|
||||||
|
ImportDirectory();
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetadataDatabase::UpdateMetadata(CollectionInfo *collection)
|
bool MetadataDatabase::ImportDirectory()
|
||||||
|
{
|
||||||
|
DIR *dp;
|
||||||
|
struct dirent *dirp;
|
||||||
|
std::string metaPath = "Meta";
|
||||||
|
dp = opendir(metaPath.c_str());
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
// if(basename.length() > 0)
|
||||||
|
{
|
||||||
|
std::string extension = basename.substr(basename.find_last_of("."), basename.size()-1);
|
||||||
|
basename = basename.substr(0, basename.find_last_of("."));
|
||||||
|
std::string collectionName = basename.substr(0, basename.find_first_of("."));
|
||||||
|
|
||||||
|
|
||||||
|
std::string type = "";
|
||||||
|
|
||||||
|
if(collectionName.length() < basename.length())
|
||||||
|
{
|
||||||
|
type = basename.substr(collectionName.length() + 1, basename.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(type == "hyperlist" && extension == ".xml")
|
||||||
|
{
|
||||||
|
std::string importFile = Configuration::GetAbsolutePath() + "/" + metaPath + "/" + dirp->d_name;
|
||||||
|
Logger::Write(Logger::ZONE_INFO, "Metadata", "Importing hyperlist: " + importFile);
|
||||||
|
ImportHyperList(importFile, collectionName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MetadataDatabase::InjectMetadata(CollectionInfo *collection)
|
||||||
{
|
{
|
||||||
sqlite3 *handle = DBInstance.GetHandle();
|
sqlite3 *handle = DBInstance.GetHandle();
|
||||||
int rc;
|
int rc;
|
||||||
@@ -130,7 +175,7 @@ void MetadataDatabase::UpdateMetadata(CollectionInfo *collection)
|
|||||||
"FROM Meta WHERE collectionName=? ORDER BY title ASC;",
|
"FROM Meta WHERE collectionName=? ORDER BY title ASC;",
|
||||||
-1, &stmt, 0);
|
-1, &stmt, 0);
|
||||||
|
|
||||||
sqlite3_bind_text(stmt, 1, collection->GetName().c_str(), -1, SQLITE_TRANSIENT);
|
sqlite3_bind_text(stmt, 1, collection->GetMetadataType().c_str(), -1, SQLITE_TRANSIENT);
|
||||||
|
|
||||||
rc = sqlite3_step(stmt);
|
rc = sqlite3_step(stmt);
|
||||||
|
|
||||||
@@ -196,3 +241,114 @@ void MetadataDatabase::UpdateMetadata(CollectionInfo *collection)
|
|||||||
rc = sqlite3_step(stmt);
|
rc = sqlite3_step(stmt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MetadataDatabase::NeedsRefresh()
|
||||||
|
{
|
||||||
|
sqlite3 *handle = DBInstance.GetHandle();
|
||||||
|
sqlite3_stmt *stmt;
|
||||||
|
|
||||||
|
sqlite3_prepare_v2(handle,
|
||||||
|
"SELECT COUNT(*) FROM Meta;",
|
||||||
|
-1, &stmt, 0);
|
||||||
|
|
||||||
|
int rc = sqlite3_step(stmt);
|
||||||
|
|
||||||
|
if(rc == SQLITE_ROW)
|
||||||
|
{
|
||||||
|
int count = sqlite3_column_int(stmt, 0);
|
||||||
|
|
||||||
|
return (count == 0) ? true : false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MetadataDatabase::ImportHyperList(std::string hyperlistFile, std::string collectionName)
|
||||||
|
{
|
||||||
|
bool retVal = false;
|
||||||
|
char *error = NULL;
|
||||||
|
rapidxml::xml_document<> doc;
|
||||||
|
std::ifstream file(hyperlistFile.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("menu");
|
||||||
|
|
||||||
|
if(!root)
|
||||||
|
{
|
||||||
|
Logger::Write(Logger::ZONE_ERROR, "Metadata", "Does not appear to be a HyperList file (missing <menu> tag)");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sqlite3 *handle = DBInstance.GetHandle();
|
||||||
|
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_attribute<> *nameXml = game->first_attribute("name");
|
||||||
|
rapidxml::xml_node<> *descriptionXml = game->first_node("description");
|
||||||
|
rapidxml::xml_node<> *cloneofXml = game->first_node("cloneof");
|
||||||
|
rapidxml::xml_node<> *crcXml = game->first_node("crc");
|
||||||
|
rapidxml::xml_node<> *manufacturerXml = game->first_node("manufacturer");
|
||||||
|
rapidxml::xml_node<> *yearXml = game->first_node("year");
|
||||||
|
rapidxml::xml_node<> *genreXml = game->first_node("genre");
|
||||||
|
rapidxml::xml_node<> *ratingXml = game->first_node("rating");
|
||||||
|
rapidxml::xml_node<> *enabledXml = game->first_node("enabled");
|
||||||
|
std::string name = (nameXml) ? nameXml->value() : "";
|
||||||
|
std::string description = (descriptionXml) ? descriptionXml->value() : "";
|
||||||
|
std::string crc = (crcXml) ? crcXml->value() : "";
|
||||||
|
std::string cloneOf = (cloneofXml) ? cloneofXml->value() : "";
|
||||||
|
std::string manufacturer = (manufacturerXml) ? manufacturerXml->value() : "";
|
||||||
|
std::string year = (yearXml) ? yearXml->value() : "";
|
||||||
|
std::string genre = (genreXml) ? genreXml->value() : "";
|
||||||
|
std::string rating = (ratingXml) ? ratingXml->value() : "";
|
||||||
|
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, cloneOf, collectionName) 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, cloneOf.c_str(), -1, SQLITE_TRANSIENT);
|
||||||
|
sqlite3_bind_text(stmt, 6, collectionName.c_str(), -1, SQLITE_TRANSIENT);
|
||||||
|
|
||||||
|
sqlite3_step(stmt);
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sqlite3_exec(handle, "COMMIT TRANSACTION;", NULL, NULL, &error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 hyperlist file. Reason: " + what);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,9 +20,12 @@ public:
|
|||||||
bool Initialize();
|
bool Initialize();
|
||||||
bool ResetDatabase();
|
bool ResetDatabase();
|
||||||
|
|
||||||
void UpdateMetadata(CollectionInfo *collection);
|
void InjectMetadata(CollectionInfo *collection);
|
||||||
|
bool ImportHyperList(std::string hyperlistFile, std::string collectionName);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool ImportDirectory();
|
||||||
|
bool NeedsRefresh();
|
||||||
Configuration &Config;
|
Configuration &Config;
|
||||||
DB &DBInstance;
|
DB &DBInstance;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Database/Configuration.h"
|
#include "Database/Configuration.h"
|
||||||
#include "Database/CollectionDatabase.h"
|
|
||||||
#include "Database/MamelistMetadata.h"
|
#include "Database/MamelistMetadata.h"
|
||||||
#include "Execute/Launcher.h"
|
#include "Execute/Launcher.h"
|
||||||
#include "Utility/Log.h"
|
#include "Utility/Log.h"
|
||||||
|
|||||||
@@ -91,6 +91,14 @@ int RetroFE::Initialize(void *context)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
instance->MetaDb = new MetadataDatabase(*(instance->Db), instance->Config);
|
||||||
|
|
||||||
|
if(!instance->MetaDb->Initialize())
|
||||||
|
{
|
||||||
|
Logger::Write(Logger::ZONE_ERROR, "RetroFE", "Could not initialize meta database");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
instance->Config.GetProperty("videoEnable", videoEnable);
|
instance->Config.GetProperty("videoEnable", videoEnable);
|
||||||
instance->Config.GetProperty("videoLoop", videoLoop);
|
instance->Config.GetProperty("videoLoop", videoLoop);
|
||||||
|
|
||||||
@@ -164,6 +172,12 @@ bool RetroFE::DeInitialize()
|
|||||||
delete page;
|
delete page;
|
||||||
PageChain.pop_back();
|
PageChain.pop_back();
|
||||||
}
|
}
|
||||||
|
if(MetaDb)
|
||||||
|
{
|
||||||
|
delete MetaDb;
|
||||||
|
MetaDb = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if(Db)
|
if(Db)
|
||||||
{
|
{
|
||||||
delete Db;
|
delete Db;
|
||||||
@@ -499,7 +513,7 @@ CollectionInfo *RetroFE::GetCollection(std::string collectionName)
|
|||||||
// the page will deallocate this once its done
|
// the page will deallocate this once its done
|
||||||
MenuParser mp;
|
MenuParser mp;
|
||||||
|
|
||||||
CollectionInfoBuilder cib(Config, *Db);
|
CollectionInfoBuilder cib(Config, *MetaDb);
|
||||||
CollectionInfo *collection = cib.BuildCollection(collectionName);
|
CollectionInfo *collection = cib.BuildCollection(collectionName);
|
||||||
mp.GetMenuItems(collection);
|
mp.GetMenuItems(collection);
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "Collection/Item.h"
|
#include "Collection/Item.h"
|
||||||
#include "Control/UserInput.h"
|
#include "Control/UserInput.h"
|
||||||
#include "Database/DB.h"
|
#include "Database/DB.h"
|
||||||
|
#include "Database/MetadataDatabase.h"
|
||||||
#include "Execute/AttractMode.h"
|
#include "Execute/AttractMode.h"
|
||||||
#include "Graphics/FontCache.h"
|
#include "Graphics/FontCache.h"
|
||||||
#include "Video/IVideo.h"
|
#include "Video/IVideo.h"
|
||||||
@@ -58,6 +59,7 @@ private:
|
|||||||
CollectionInfo *GetCollection(std::string collectionName);
|
CollectionInfo *GetCollection(std::string collectionName);
|
||||||
Configuration &Config;
|
Configuration &Config;
|
||||||
DB *Db;
|
DB *Db;
|
||||||
|
MetadataDatabase *MetaDb;
|
||||||
UserInput Input;
|
UserInput Input;
|
||||||
std::list<Page *> PageChain;
|
std::list<Page *> PageChain;
|
||||||
float KeyInputDisable;
|
float KeyInputDisable;
|
||||||
|
|||||||
Reference in New Issue
Block a user