From c2412b3c1850dfbe4c5ed37b5f02c9a3614c8fc3 Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Sun, 11 Mar 2018 17:58:03 +0000 Subject: [PATCH] Implement loading and saving EPG filters --- vdrclient.c | 216 ++++++++++++++++++++++++++++++++++++++++++++++++++++ vdrclient.h | 14 +++- 2 files changed, 229 insertions(+), 1 deletion(-) diff --git a/vdrclient.c b/vdrclient.c index a68b9f8..f49c96f 100644 --- a/vdrclient.c +++ b/vdrclient.c @@ -14,6 +14,7 @@ critical #include #include +#include #include #include #include @@ -24,6 +25,12 @@ VDRClient::VDRClient() logger = spd::get("jsonserver_spdlog"); } +VDRClient::~VDRClient() +{ + logger->debug("VDRClient destructor"); + saveEpgFilter(); +} + bool VDRClient::process(std::string& request, PFMap& postFields, std::string& returnString) { Json::Value returnJSON; @@ -38,6 +45,7 @@ bool VDRClient::process(std::string& request, PFMap& postFields, std::string& re else if (request == "timerlist") success = timerlist(postFields, returnJSON); else if (request == "epgdownload") success = epgdownload(postFields, returnJSON); else if (request == "tunersstatus") success = tunersstatus(postFields, returnJSON); + else if (request == "epgfilterget") success = epgfilterget(postFields, returnJSON); else if (request == "channelschedule") success = channelschedule(postFields, returnJSON); else if (request == "getscheduleevent") success = getscheduleevent(postFields, returnJSON); @@ -54,6 +62,8 @@ bool VDRClient::process(std::string& request, PFMap& postFields, std::string& re else if (request == "timerisrecording") success = timerisrecording(postFields, returnJSON); else if (request == "recresetresume") success = recresetresume(postFields, returnJSON); else if (request == "timeredit") success = timeredit(postFields, returnJSON); + else if (request == "epgfilteradd") success = epgfilteradd(postFields, returnJSON); + else if (request == "epgfilterdel") success = epgfilterdel(postFields, returnJSON); } catch (BadParamException e) { @@ -1315,6 +1325,134 @@ bool VDRClient::timeredit(PFMap& postFields, Json::Value& js) // RETHROWS return true; } +bool VDRClient::epgfilteradd(PFMap& postFields, Json::Value& js) // RETHROWS +{ + std::string channel = getVarString(postFields, "channel"); + std::string programme = getVarString(postFields, "programme"); + + logger->debug("epgFilterAdd: {} {}", channel, programme); + + if (!loadEpgFilter()) + { + js["Result"] = false; + js["Error"] = "Error initialising EPG filter"; + return true; + } + + libconfig::Setting& setting = epgFilter.lookup("filters"); + libconfig::Setting& newPair = setting.add(libconfig::Setting::Type::TypeGroup); + libconfig::Setting& newChannel = newPair.add("c", libconfig::Setting::Type::TypeString); + newChannel = channel; + libconfig::Setting& newProgramme = newPair.add("p", libconfig::Setting::Type::TypeString); + newProgramme = programme; + + js["Result"] = true; + return true; +} + +bool VDRClient::epgfilterdel(PFMap& postFields, Json::Value& js) // RETHROWS +{ + std::string channel = getVarString(postFields, "channel"); + std::string programme = getVarString(postFields, "programme"); + + logger->debug("epgFilterDel: {} {}", channel, programme); + + if (!loadEpgFilter()) + { + js["Result"] = false; + js["Error"] = "Error initialising EPG filter"; + return true; + } + + try + { + libconfig::Setting& setting = epgFilter.lookup("filters"); + int numFilters = setting.getLength(); + int x; + for (x = 0; x < numFilters; x++) + { + libconfig::Setting& pair = setting[x]; + std::string c; + std::string p; + if (!pair.lookupValue("c", c) || !pair.lookupValue("p", p)) + { + js["Result"] = false; + js["Error"] = "Filter file format error"; + return true; + } + logger->debug("loop: {} {}", c, p); + if ((c == channel) && (p == programme)) + { + setting.remove(x); + logger->debug("Found and deleted: {} {}", c, p); + break; + } + } + if (x == numFilters) + { + js["Result"] = false; + js["Error"] = "Channel/Programme not found"; + return true; + } + } + catch (std::exception e) + { + js["Result"] = false; + js["Error"] = "Unknown error"; + return true; + } + + js["Result"] = true; + return true; +} + +bool VDRClient::epgfilterget(PFMap& postFields, Json::Value& js) // RETHROWS +{ + logger->debug("epgFilterget"); + + if (!loadEpgFilter()) + { + js["Result"] = false; + js["Error"] = "Error initialising EPG filter"; + return true; + } + + try + { + libconfig::Setting& setting = epgFilter.lookup("filters"); + int numFilters = setting.getLength(); + int x; + Json::Value jsfilters(Json::arrayValue); + for (x = 0; x < numFilters; x++) + { + libconfig::Setting& pair = setting[x]; + std::string c; + std::string p; + if (!pair.lookupValue("c", c) || !pair.lookupValue("p", p)) + { + js["Result"] = false; + js["Error"] = "Filter file format error"; + return true; + } + logger->debug("loop: {} {}", c, p); + Json::Value oneFilter; + oneFilter["c"] = c; + oneFilter["p"] = p; + jsfilters.append(oneFilter); + } + js["EPG Filters"] = jsfilters; + } + catch (std::exception e) + { + js["Result"] = false; + js["Error"] = "Unknown error"; + return true; + } + + js["Result"] = true; + return true; +} + ////////////////////////////////////////////////////////////////////////////////////////////////// const cEvent* VDRClient::getEvent(Json::Value& js, int channelNumber, int eventID, int aroundTime) @@ -1451,3 +1589,81 @@ std::string VDRClient::getVarString(PFMap& postFields, const char* paramName) // if (i->second.empty()) throw BadParamException(paramName); return i->second; } + +bool VDRClient::loadEpgFilter() +{ + if (epgFilterLoaded) return true; + + const char* configDir = cPlugin::ConfigDirectory("jsonserver"); + if (!configDir) + { + logger->error("loadEpgFilter: Error: Could not get config dir from VDR"); + return false; + } + + std::string epgFilterFile(std::string(configDir) + std::string("/epgfilter.conf")); + FILE* fp = fopen(epgFilterFile.c_str(), "a"); + if (!fp) + { + logger->error("loadEpgFilter: Error: Failed to fopen epgfilter.conf"); + return false; + } + fclose(fp); + + try + { + epgFilter.readFile(epgFilterFile.c_str()); + } + catch (const libconfig::FileIOException &fioex) + { + logger->error("loadEpgFilter: Error: Failed to read filter file"); + return false; + } + catch(const libconfig::ParseException &pex) + { + logger->error("loadEpgFilter: Parse error at {}: {} - {}", pex.getFile(), pex.getLine(), pex.getError()); + return false; + } + + try + { + libconfig::Setting& setting = epgFilter.lookup("filters"); + + if (!setting.isList()) + { + logger->error("loadEpgFilter: Error: Failed to read filter file (2)"); + return false; + } + } + catch (libconfig::SettingNotFoundException e) + { + libconfig::Setting& setting = epgFilter.getRoot(); + setting.add("filters", libconfig::Setting::Type::TypeList); + } + + epgFilterLoaded = true; + return true; +} + +void VDRClient::saveEpgFilter() +{ + if (!epgFilterLoaded) return; + + const char* configDir = cPlugin::ConfigDirectory("jsonserver"); + if (!configDir) + { + logger->error("saveEpgFilter: Error: Could not get config dir from VDR"); + return; + } + + std::string epgFilterFile(std::string(configDir) + std::string("/epgfilter.conf")); + try + { + epgFilter.writeFile(epgFilterFile.c_str()); + logger->debug("saveEpgFilter: EPG filter saved"); + } + catch (const libconfig::FileIOException& e) + { + logger->error("saveEpgFilter: Error: File write error"); + } +} diff --git a/vdrclient.h b/vdrclient.h index 75ec278..2897864 100644 --- a/vdrclient.h +++ b/vdrclient.h @@ -7,6 +7,9 @@ #include namespace spd = spdlog; +// Config docs: http://www.hyperrealm.com/libconfig/libconfig_manual.html#The-C_002b_002b-API +#include + class cEvent; class cTimer; @@ -16,6 +19,7 @@ class VDRClient public: VDRClient(); + ~VDRClient(); bool process(std::string& request, PFMap& postFields, std::string& returnData); @@ -28,6 +32,7 @@ class VDRClient bool timerlist(PFMap& postFields, Json::Value& returnJSON); bool epgdownload(PFMap& postFields, Json::Value& returnJSON); bool tunersstatus(PFMap& postFields, Json::Value& returnJSON); + bool epgfilterget(PFMap& postFields, Json::Value& js); bool channelschedule(PFMap& postFields, Json::Value& returnJSON); // throws BadParamException bool getscheduleevent(PFMap& postFields, Json::Value& returnJSON); // throws BadParamException @@ -43,7 +48,9 @@ class VDRClient bool timerdel(PFMap& postFields, Json::Value& returnJSON); // throws BadParamException bool timerisrecording(PFMap& postFields, Json::Value& returnJSON); // throws BadParamException bool recresetresume(PFMap& postFields, Json::Value& returnJSON); // throws BadParamException - bool timeredit(PFMap& postFields, Json::Value& returnJSON); + bool timeredit(PFMap& postFields, Json::Value& returnJSON); // throws BadParamException + bool epgfilteradd(PFMap& postFields, Json::Value& returnJSON); // throws BadParamException + bool epgfilterdel(PFMap& postFields, Json::Value& js); // throws BadParamException cTimer* findTimer(const char* rChannelID, const char* rName, const char* rStartTime, const char* rStopTime, const char* rWeekDays); cTimer* findTimer2(const char* rName, const char* rActive, const char* rChannelID, const char* rDay, const char* rWeekDays, const char* rStartTime, const char* rStopTime, const char* rPriority, const char* rLifetime); @@ -59,6 +66,11 @@ class VDRClient int getVarInt(PFMap& postFields, const char* paramName); // THROWS std::string getVarString(PFMap& postFields, const char* paramName); // THROWS + libconfig::Config epgFilter; + bool epgFilterLoaded = false; + bool loadEpgFilter(); + void saveEpgFilter(); + class BadParamException : public std::exception { public: -- 2.39.2