Implement loading and saving EPG filters
authorChris Tallon <chris@vomp.tv>
Sun, 11 Mar 2018 17:58:03 +0000 (17:58 +0000)
committerChris Tallon <chris@vomp.tv>
Sun, 11 Mar 2018 17:58:03 +0000 (17:58 +0000)
vdrclient.c
vdrclient.h

index a68b9f8ce5a5fc787358c0f85daaa0963973c750..f49c96f5d6fc5c6bd50cac3922f41c84f9b29371 100644 (file)
@@ -14,6 +14,7 @@ critical
 #include <sys/time.h>
 #include <string>
 
+#include <vdr/plugin.h>
 #include <vdr/videodir.h>
 #include <vdr/recording.h>
 #include <vdr/menu.h>
@@ -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");
+  }
+}
index 75ec2785dec5144bff3db379d60e47d2a24c1046..28978642c9c6597e797b596e39e0fe6972545594 100644 (file)
@@ -7,6 +7,9 @@
 #include <spdlog/spdlog.h>
 namespace spd = spdlog;
 
+// Config docs: http://www.hyperrealm.com/libconfig/libconfig_manual.html#The-C_002b_002b-API
+#include <libconfig.h++>
+
 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: