]> git.vomp.tv Git - jsonserver.git/commitdiff
Compatibility with VDR 2.3.1. Min VDR version now 2.3.1.
authorChris Tallon <chris@vomp.tv>
Thu, 1 Aug 2019 15:23:36 +0000 (16:23 +0100)
committerChris Tallon <chris@vomp.tv>
Thu, 1 Aug 2019 15:23:36 +0000 (16:23 +0100)
vdrclient.c
vdrclient.h

index e118ed836bb91f820ee56374a8dac8e818ffb1d3..d441ea5460d97427b82c6e4c78f5fb33d83e023b 100644 (file)
@@ -19,6 +19,12 @@ critical
 #include <vdr/recording.h>
 #include <vdr/menu.h>
 #include <vdr/timers.h>
+#include <vdr/channels.h>
+
+/* Locking information from VDR:
++ If a plugin needs to access several of the global lists in parallel, locking must
+  always be done in the sequence Timers, Channels, Recordings, Schedules.
+*/
 
 VDRClient::VDRClient()
 {
@@ -65,7 +71,7 @@ bool VDRClient::process(std::string& request, PFMap& postFields, std::string& re
     else if (request == "epgfilteradd")      success = epgfilteradd(postFields, returnJSON);
     else if (request == "epgfilterdel")      success = epgfilterdel(postFields, returnJSON);
   }
-  catch (BadParamException e)
+  catch (const BadParamException& e)
   {
     logger->error("Bad parameter in call, paramName: {}", e.param);
     returnJSON["Result"] = false;
@@ -116,7 +122,9 @@ bool VDRClient::channellist(PFMap& postFields, Json::Value& js)
 
   Json::Value jschannels(Json::arrayValue);
 
-  for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
+  LOCK_CHANNELS_READ;
+
+  for (const cChannel *channel = Channels->First(); channel; channel = Channels->Next(channel))
   {
     if (!channel->GroupSep())
     {
@@ -137,9 +145,10 @@ bool VDRClient::reclist(PFMap& postFields, Json::Value& js)
   logger->debug("reclist");
 
   Json::Value jsrecordings(Json::arrayValue);
-  cRecordings Recordings;
-  Recordings.Load();
-  for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording))
+
+  LOCK_RECORDINGS_READ;
+
+  for (const cRecording *recording = Recordings->First(); recording; recording = Recordings->Next(recording))
   {
     Json::Value oneRec;
     oneRec["StartTime"] = (Json::UInt)recording->Start();
@@ -166,12 +175,17 @@ bool VDRClient::timerlist(PFMap& postFields, Json::Value& js)
 
   Json::Value jstimers(Json::arrayValue);
 
-  cTimer *timer;
-  int numTimers = Timers.Count();
+  const cTimer *timer;
+
+  LOCK_TIMERS_READ;
+  LOCK_CHANNELS_READ;
+  LOCK_SCHEDULES_READ;
+
+  int numTimers = Timers->Count();
 
   for (int i = 0; i < numTimers; i++)
   {
-    timer = Timers.Get(i);
+    timer = Timers->Get(i);
     Json::Value oneTimer;
     oneTimer["Active"] = timer->HasFlags(tfActive);
     oneTimer["Recording"] = timer->Recording();
@@ -195,7 +209,7 @@ bool VDRClient::timerlist(PFMap& postFields, Json::Value& js)
     {
       int channelNumber = timer->Channel()->Number();
       int aroundTime = timer->StartTime() + 1;
-      const cEvent* eventAround = getEvent(js, channelNumber, 0, aroundTime);
+      const cEvent* eventAround = getEvent(Channels, Schedules, js, channelNumber, 0, aroundTime);
       if (eventAround)
       {
         oneTimer["EventID"] = eventAround->EventID();
@@ -222,8 +236,12 @@ bool VDRClient::channelschedule(PFMap& postFields, Json::Value& js) // RETHROWS
   int startTime = getVarInt(postFields, "starttime");
   int duration = getVarInt(postFields, "duration");
 
-  cChannel* channel = NULL;
-  for (channel = Channels.First(); channel; channel = Channels.Next(channel))
+  Json::Value jsevents(Json::arrayValue);
+
+  LOCK_CHANNELS_READ;
+
+  const cChannel* channel = NULL;
+  for (channel = Channels->First(); channel; channel = Channels->Next(channel))
   {
     if (channel->GroupSep()) continue;
     if (channel->Number() == channelNumber) break;
@@ -237,15 +255,8 @@ bool VDRClient::channelschedule(PFMap& postFields, Json::Value& js) // RETHROWS
     return true;
   }
 
-  cSchedulesLock MutexLock;
-  const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
-  if (!Schedules)
-  {
-    logger->error("channelschedule: Could not find requested channel: {}", channelNumber);
-    js["Result"] = false;
-    js["Error"] = "Internal schedules error (1)";
-    return true;
-  }
+  LOCK_SCHEDULES_READ;
+
   const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
   if (!Schedule)
   {
@@ -255,8 +266,6 @@ bool VDRClient::channelschedule(PFMap& postFields, Json::Value& js) // RETHROWS
     return true;
   }
 
-  Json::Value jsevents(Json::arrayValue);
-
   for (const cEvent* event = Schedule->Events()->First(); event; event = Schedule->Events()->Next(event))
   {
     if ((event->StartTime() + event->Duration()) < time(NULL)) continue; //in the past filter
@@ -285,7 +294,10 @@ bool VDRClient::getscheduleevent(PFMap& postFields, Json::Value& js) // RETHROWS
   int channelNumber = getVarInt(postFields, "channelnumber");
   int eventID = getVarInt(postFields, "eventid");
 
-  const cEvent* event = getEvent(js, channelNumber, eventID, 0);
+  LOCK_CHANNELS_READ;
+  LOCK_SCHEDULES_READ;
+
+  const cEvent* event = getEvent(Channels, Schedules, js, channelNumber, eventID, 0);
   if (!event)
   {
     js["Result"] = false;
@@ -310,28 +322,18 @@ bool VDRClient::getscheduleevent(PFMap& postFields, Json::Value& js) // RETHROWS
 bool VDRClient::epgdownload(PFMap& postFields, Json::Value& js)
 {
   logger->debug("epgdownload");
-
-  cSchedulesLock MutexLock;
-  const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
-
-  if (!Schedules)
-  {
-    logger->error("epgdownload: Could not get Schedules object");
-    js["Result"] = false;
-    js["Error"] = "Internal schedules error (1)";
-    return true;
-  }
-
   Json::Value jsevents(Json::arrayValue);
 
-  for (cChannel* channel = Channels.First(); channel; channel = Channels.Next(channel))
+  LOCK_CHANNELS_READ;
+  LOCK_SCHEDULES_READ;
+
+  for (const cChannel* channel = Channels->First(); channel; channel = Channels->Next(channel))
   {
     if (channel->GroupSep()) continue;
 
     const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
     if (!Schedule) continue;
 
-
     for (const cEvent* event = Schedule->Events()->First(); event; event = Schedule->Events()->Next(event))
     {
       Json::Value oneEvent;
@@ -360,20 +362,12 @@ bool VDRClient::epgsearch(PFMap& postFields, Json::Value& js) // RETHROWS
   std::string searchfor = getVarString(postFields, "searchfor");
   logger->debug("epgsearch: search for: {}", searchfor);
 
-  cSchedulesLock MutexLock;
-  const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
-
-  if (!Schedules)
-  {
-    logger->error("epgsearch: Could not get Schedules object");
-    js["Result"] = false;
-    js["Error"] = "Internal schedules error (1)";
-    return true;
-  }
-
   Json::Value jsevents(Json::arrayValue);
 
-  for (cChannel* channel = Channels.First(); channel; channel = Channels.Next(channel))
+  LOCK_CHANNELS_READ;
+  LOCK_SCHEDULES_READ;
+
+  for (const cChannel* channel = Channels->First(); channel; channel = Channels->Next(channel))
   {
     if (channel->GroupSep()) continue;
 
@@ -430,18 +424,12 @@ bool VDRClient::epgsearchsame(PFMap& postFields, Json::Value& js) // RETHROWS
 
   logger->debug("epgsearchsame: request time: {}, title: {}", atTime, sTitle);
 
-  cSchedulesLock SchedulesLock;
-  const cSchedules *schedules = cSchedules::Schedules(SchedulesLock);
-  if (!schedules)
-  {
-    js["Result"] = false;
-    return true;
-  }
-
   Json::Value jsevents(Json::arrayValue);
-
   const cEvent *event;
-  for (cSchedule *schedule = schedules->First(); (schedule != NULL); schedule = schedules->Next(schedule))
+
+  LOCK_SCHEDULES_READ;
+
+  for (const cSchedule *schedule = Schedules->First(); (schedule != NULL); schedule = Schedules->Next(schedule))
   {
     event = schedule->GetEventAround(atTime);
     if (!event) continue; // nothing found on this schedule(channel)
@@ -471,9 +459,11 @@ bool VDRClient::epgsearchotherhalf(PFMap& postFields, Json::Value& js) // RETHRO
   logger->debug("epgsearchotherhalf");
   int channelNumber = getVarInt(postFields, "channelnumber");
   int eventID = getVarInt(postFields, "eventid");
+  const cChannel* channel = NULL;
+
+  LOCK_CHANNELS_READ;
 
-  cChannel* channel = NULL;
-  for (channel = Channels.First(); channel; channel = Channels.Next(channel))
+  for (channel = Channels->First(); channel; channel = Channels->Next(channel))
   {
     if (channel->GroupSep()) continue;
     if (channel->Number() == channelNumber) break;
@@ -487,15 +477,8 @@ bool VDRClient::epgsearchotherhalf(PFMap& postFields, Json::Value& js) // RETHRO
     return true;
   }
 
-  cSchedulesLock MutexLock;
-  const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
-  if (!Schedules)
-  {
-    logger->error("epgsearchotherhalf: Could not find requested channel: {}", channelNumber);
-    js["Result"] = false;
-    js["Error"] = "Internal schedules error (1)";
-    return true;
-  }
+  LOCK_SCHEDULES_READ;
+
   const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
   if (!Schedule)
   {
@@ -596,11 +579,15 @@ bool VDRClient::tunersstatus(PFMap& postFields, Json::Value& js)
 
 
   Json::Value jstimers(Json::arrayValue);
-  int numTimers = Timers.Count();
-  cTimer* timer;
+
+  LOCK_TIMERS_READ;
+  LOCK_CHANNELS_READ; // Because this calls timer->Channel() .. necessary?
+
+  int numTimers = Timers->Count();
+  const cTimer* timer;
   for (int i = 0; i < numTimers; i++)
   {
-    timer = Timers.Get(i);
+    timer = Timers->Get(i);
 
     if (timer->Recording())
     {
@@ -658,7 +645,10 @@ bool VDRClient::timerset(PFMap& postFields, Json::Value& js) // RETHROWS
     return true;
   }
 
-  cTimer *t = Timers.GetTimer(timer);
+  LOCK_TIMERS_WRITE;
+  Timers->SetExplicitModify();
+
+  cTimer *t = Timers->GetTimer(timer);
   if (t)
   {
     delete timer;
@@ -667,8 +657,9 @@ bool VDRClient::timerset(PFMap& postFields, Json::Value& js) // RETHROWS
     return true;
   }
 
-  Timers.Add(timer);
-  Timers.SetModified();
+  Timers->Add(timer);
+  Timers->SetModified();
+
   js["Result"] = true;
   return true;
 }
@@ -680,9 +671,9 @@ bool VDRClient::recinfo(PFMap& postFields, Json::Value& js) // RETHROWS
   std::string reqfilename = getVarString(postFields, "filename");
   logger->debug("recinfo: {}", reqfilename);
 
-  cRecordings Recordings;
-  Recordings.Load(); // probably have to do this
-  cRecording *recording = Recordings.GetByName(reqfilename.c_str());
+  LOCK_RECORDINGS_READ;
+
+  const cRecording *recording = Recordings->GetByName(reqfilename.c_str());
 
   if (!recording)
   {
@@ -758,9 +749,10 @@ bool VDRClient::recstop(PFMap& postFields, Json::Value& js) // RETHROWS
   std::string reqfilename = getVarString(postFields, "filename");
   logger->debug("recstop: {}", reqfilename);
 
-  cRecordings Recordings;
-  Recordings.Load(); // probably have to do this
-  cRecording *recording = Recordings.GetByName(reqfilename.c_str());
+  LOCK_TIMERS_WRITE;
+  LOCK_RECORDINGS_WRITE; // May not need write here, but to be safe..
+
+  cRecording *recording = Recordings->GetByName(reqfilename.c_str());
 
   if (!recording)
   {
@@ -777,13 +769,6 @@ bool VDRClient::recstop(PFMap& postFields, Json::Value& js) // RETHROWS
     return true;
   }
 
-  if (Timers.BeingEdited())
-  {
-    logger->debug("recstop: timers being edited elsewhere");
-    js["Result"] = false;
-    return true;
-  }
-
   cTimer* timer = rc->Timer();
   if (!timer)
   {
@@ -793,7 +778,6 @@ bool VDRClient::recstop(PFMap& postFields, Json::Value& js) // RETHROWS
   }
 
   timer->ClrFlags(tfActive);
-  Timers.SetModified();
 
   js["Result"] = true;
   return true;
@@ -807,9 +791,9 @@ bool VDRClient::recdel(PFMap& postFields, Json::Value& js) // RETHROWS
   std::string reqfilename = getVarString(postFields, "filename");
   logger->debug("recdel: {}", reqfilename);
 
-  cRecordings Recordings;
-  Recordings.Load(); // probably have to do this
-  cRecording *recording = Recordings.GetByName(reqfilename.c_str());
+  LOCK_RECORDINGS_WRITE;
+
+  cRecording *recording = Recordings->GetByName(reqfilename.c_str());
 
   if (!recording)
   {
@@ -829,7 +813,7 @@ bool VDRClient::recdel(PFMap& postFields, Json::Value& js) // RETHROWS
 
   if (recording->Delete())
   {
-    ::Recordings.DelByName(recording->FileName());
+    Recordings->DelByName(recording->FileName());
     js["Result"] = true;
   }
   else
@@ -841,27 +825,28 @@ bool VDRClient::recdel(PFMap& postFields, Json::Value& js) // RETHROWS
   return true;
 }
 
-void VDRClient::pathsForRecordingName(const std::string& recordingName,
+void VDRClient::pathsForRecordingName(const cRecordings* Recordings, const std::string& recordingName,
                            std::string& dirNameSingleDate,
                            std::string& dirNameSingleTitle,
                            std::string& dirNameSingleFolder,
                            std::string& dirNameFullPathTitle,
                            std::string& dirNameFullPathDate)  // throws int
 {
-  cRecordings Recordings;
-  Recordings.Load();
-  cRecording* recordingObj = Recordings.GetByName(recordingName.c_str());
-  if (!recordingObj) throw 2;
+  const char* t;
+  {
+    const cRecording* recordingObj = Recordings->GetByName(recordingName.c_str());
+    if (!recordingObj) throw 2;
+    t = recordingObj->FileName();
 
-  cRecordControl *rc = cRecordControls::GetRecordControl(recordingObj->FileName());
-  if (rc) throw 3;
+    cRecordControl *rc = cRecordControls::GetRecordControl(recordingObj->FileName());
+    if (rc) throw 3;
 
-  logger->debug("paths: recording: {}", recordingObj->Name());
-  logger->debug("paths: recording: {}", recordingObj->FileName());
+    logger->debug("paths: recording: {}", recordingObj->Name());
+  } // unlock recordings
 
-  const char* t = recordingObj->FileName();
-  dirNameFullPathDate = t;
+  logger->debug("paths: recording: {}", t);
 
+  dirNameFullPathDate = t;
   int k, j, m;
 
   // Find the datedirname
@@ -926,9 +911,14 @@ bool VDRClient::recrename(PFMap& postFields, Json::Value& js) // RETHROWS
   std::string dirNameFullPathTitle;
   std::string dirNameFullPathDate;
 
+#warning Switch this to Recording->ChangeName ?
+
   try
   {
-    pathsForRecordingName(fileNameToAffect, dirNameSingleDate,
+    LOCK_RECORDINGS_WRITE;
+
+    pathsForRecordingName(Recordings,
+                          fileNameToAffect, dirNameSingleDate,
                           dirNameSingleTitle, dirNameSingleFolder,
                           dirNameFullPathTitle, dirNameFullPathDate);
 
@@ -984,7 +974,7 @@ bool VDRClient::recrename(PFMap& postFields, Json::Value& js) // RETHROWS
     // Success. Test for remove old dir containter
     rmdir(dirNameFullPathTitle.c_str()); // can't do anything about a fail result at this point.
 
-    ::Recordings.Update();
+    Recordings->Update();
     js["Result"] = true;
     js["NewRecordingFileName"] = newDirNameFullPathDate;
   }
@@ -1046,7 +1036,10 @@ bool VDRClient::recmove(PFMap& postFields, Json::Value& js) // RETHROWS
 
   try
   {
-    pathsForRecordingName(fileNameToAffect, dirNameSingleDate,
+    LOCK_RECORDINGS_WRITE;
+
+    pathsForRecordingName(Recordings,
+                          fileNameToAffect, dirNameSingleDate,
                           dirNameSingleTitle, dirNameSingleFolder,
                           dirNameFullPathTitle, dirNameFullPathDate);
 
@@ -1129,7 +1122,7 @@ bool VDRClient::recmove(PFMap& postFields, Json::Value& js) // RETHROWS
       rmdir(dirNameFullPathFolder.c_str()); // can't do anything about a fail result at this point.
     }
 
-    ::Recordings.Update();
+    Recordings->Update();
     js["Result"] = true;
     js["NewRecordingFileName"] = newDirNameFullPathDate;
   }
@@ -1199,20 +1192,25 @@ bool VDRClient::timersetactive(PFMap& postFields, Json::Value& js) // RETHROWS
 
   logger->debug("timersetactive: {} {}:{}:{}:{}:{}", tNewActive, rChannelID, rName, rStartTime, rStopTime, rWeekDays);
 
-  cTimer* timer = findTimer(rChannelID.c_str(), rName.c_str(), rStartTime.c_str(), rStopTime.c_str(), rWeekDays.c_str());
+  if ((tNewActive != "true") && (tNewActive != "false"))
+  {
+    js["Result"] = false;
+    js["Error"] = "Bad request parameters";
+    return true;
+  }
+
+
+  LOCK_TIMERS_WRITE;
+  Timers->SetExplicitModify();
+
+  cTimer* timer = findTimer(Timers, rChannelID.c_str(), rName.c_str(), rStartTime.c_str(), rStopTime.c_str(), rWeekDays.c_str());
   if (timer)
   {
-    if      (tNewActive == "true")  timer->SetFlags(tfActive);
-    else if (tNewActive == "false") timer->ClrFlags(tfActive);
-    else
-    {
-      js["Result"] = false;
-      js["Error"] = "Bad request parameters";
-      return true;
-    }
+    if (tNewActive == "true") timer->SetFlags(tfActive);
+    else timer->ClrFlags(tfActive);
 
     js["Result"] = true;
-    Timers.SetModified();
+    Timers->SetModified();
     return true;
   }
 
@@ -1233,15 +1231,10 @@ bool VDRClient::timerdel(PFMap& postFields, Json::Value& js) // RETHROWS
 
   logger->debug("timerdel: {}:{}:{}:{}:{}", rChannelID, rName, rStartTime, rStopTime, rWeekDays);
 
-  if (Timers.BeingEdited())
-  {
-    logger->debug("timerdel: Unable to delete timer - timers being edited at VDR");
-    js["Result"] = false;
-    js["Error"] = "Timers being edited at VDR";
-    return true;
-  }
+  LOCK_TIMERS_WRITE;
+  Timers->SetExplicitModify();
 
-  cTimer* timer = findTimer(rChannelID.c_str(), rName.c_str(), rStartTime.c_str(), rStopTime.c_str(), rWeekDays.c_str());
+  cTimer* timer = findTimer(Timers, rChannelID.c_str(), rName.c_str(), rStartTime.c_str(), rStopTime.c_str(), rWeekDays.c_str());
   if (timer)
   {
     if (timer->Recording())
@@ -1252,8 +1245,8 @@ bool VDRClient::timerdel(PFMap& postFields, Json::Value& js) // RETHROWS
       return true;
     }
 
-    Timers.Del(timer);
-    Timers.SetModified();
+    Timers->Del(timer);
+    Timers->SetModified();
     js["Result"] = true;
     return true;
   }
@@ -1275,7 +1268,9 @@ bool VDRClient::timerisrecording(PFMap& postFields, Json::Value& js) // RETHROWS
 
   logger->debug("timerisrecording: {}:{}:{}:{}:{}", rChannelID, rName, rStartTime, rStopTime, rWeekDays);
 
-  cTimer* timer = findTimer(rChannelID.c_str(), rName.c_str(), rStartTime.c_str(), rStopTime.c_str(), rWeekDays.c_str());
+  LOCK_TIMERS_READ;
+
+  const cTimer* timer = findTimer(Timers, rChannelID.c_str(), rName.c_str(), rStartTime.c_str(), rStopTime.c_str(), rWeekDays.c_str());
   if (timer)
   {
     js["Recording"] = timer->Recording();
@@ -1296,9 +1291,9 @@ bool VDRClient::recresetresume(PFMap& postFields, Json::Value& js) // RETHROWS
   std::string reqfilename = getVarString(postFields, "filename");
   logger->debug("recresetresume: {}", reqfilename);
 
-  cRecordings Recordings;
-  Recordings.Load(); // probably have to do this
-  cRecording *recording = Recordings.GetByName(reqfilename.c_str());
+  LOCK_RECORDINGS_WRITE; // may not need write, but to be safe..
+
+  cRecording *recording = Recordings->GetByName(reqfilename.c_str());
 
   if (!recording)
   {
@@ -1352,7 +1347,10 @@ bool VDRClient::timeredit(PFMap& postFields, Json::Value& js) // RETHROWS
 
   logger->debug("timeredit: {} {} {} {} {} {} {} {} {}", newName, newActive, newChannelID, newDay, newWeekDays, newStartTime, newStopTime, newPriority, newLifetime);
 
-  cTimer* timer = findTimer2(oldName.c_str(), oldActive.c_str(), oldChannelID.c_str(), oldDay.c_str(), oldWeekDays.c_str(), oldStartTime.c_str(), oldStopTime.c_str(), oldPriority.c_str(), oldLifetime.c_str());
+  LOCK_TIMERS_WRITE;
+  Timers->SetExplicitModify();
+
+  cTimer* timer = findTimer2(Timers, oldName.c_str(), oldActive.c_str(), oldChannelID.c_str(), oldDay.c_str(), oldWeekDays.c_str(), oldStartTime.c_str(), oldStopTime.c_str(), oldPriority.c_str(), oldLifetime.c_str());
   if (!timer)
   {
     js["Result"] = false;
@@ -1360,6 +1358,8 @@ bool VDRClient::timeredit(PFMap& postFields, Json::Value& js) // RETHROWS
     return true;
   }
 
+  Timers->SetModified();
+
   // Old version commented below (now removed) used to set each thing individually based on whether it had changed. However, since
   // the only way to change the timer channel appears to be with the cTimer::Parse function, might as well use that
   // for everything it supports
@@ -1413,7 +1413,6 @@ bool VDRClient::timeredit(PFMap& postFields, Json::Value& js) // RETHROWS
   }
 
   js["Result"] = true;
-  Timers.SetModified();
   return true;
 }
 
@@ -1503,7 +1502,7 @@ bool VDRClient::epgfilterdel(PFMap& postFields, Json::Value& js) // RETHROWS
     js["Error"] = "Channel/Programme not found";
     return true;
   }
-  catch (std::exception e)
+  catch (const std::exception& e)
   {
     js["Result"] = false;
     js["Error"] = "Unknown error";
@@ -1548,7 +1547,7 @@ bool VDRClient::epgfilterget(PFMap& postFields, Json::Value& js) // RETHROWS
     }
     js["EPGFilters"] = jsfilters;
   }
-  catch (std::exception e)
+  catch (const std::exception& e)
   {
     js["Result"] = false;
     js["Error"] = "Unknown error";
@@ -1561,10 +1560,12 @@ bool VDRClient::epgfilterget(PFMap& postFields, Json::Value& js) // RETHROWS
 
 //////////////////////////////////////////////////////////////////////////////////////////////////
 
-const cEvent* VDRClient::getEvent(Json::Value& js, int channelNumber, int eventID, int aroundTime)
+const cEvent* VDRClient::getEvent(const cChannels* Channels, const cSchedules* Schedules,
+                                  Json::Value& js, int channelNumber, int eventID, int aroundTime)
 {
-  cChannel* channel = NULL;
-  for (channel = Channels.First(); channel; channel = Channels.Next(channel))
+  const cChannel* channel = NULL;
+
+  for (channel = Channels->First(); channel; channel = Channels->Next(channel))
   {
     if (channel->GroupSep()) continue;
     if (channel->Number() == channelNumber) break;
@@ -1577,15 +1578,6 @@ const cEvent* VDRClient::getEvent(Json::Value& js, int channelNumber, int eventI
     return NULL;
   }
 
-  cSchedulesLock MutexLock;
-  const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
-  if (!Schedules)
-  {
-    logger->error("getevent: Could not find requested channel: {}", channelNumber);
-    js["Error"] = "Internal schedules error (1)";
-    return NULL;
-  }
-
   const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
   if (!Schedule)
   {
@@ -1610,13 +1602,52 @@ const cEvent* VDRClient::getEvent(Json::Value& js, int channelNumber, int eventI
   return event;
 }
 
-cTimer* VDRClient::findTimer(const char* rChannelID, const char* rName, const char* rStartTime, const char* rStopTime, const char* rWeekDays)
+cTimer* VDRClient::findTimer(cTimers* Timers,
+                             const char* rChannelID, const char* rName, const char* rStartTime, const char* rStopTime, const char* rWeekDays)
 {
-  int numTimers = Timers.Count();
+  int numTimers = Timers->Count();
   cTimer* timer;
   for (int i = 0; i < numTimers; i++)
   {
-    timer = Timers.Get(i);
+    timer = Timers->Get(i);
+
+    logger->debug("findtimer: current: {}", (const char*)timer->ToText(true));
+    logger->debug("findtimer: {}", (const char*)timer->Channel()->GetChannelID().ToString());
+    logger->debug("findtimer: {}", rChannelID);
+    logger->debug("findtimer: {}", timer->File());
+    logger->debug("findtimer: {}", rName);
+    logger->debug("findtimer: {}", timer->StartTime());
+    logger->debug("findtimer: {}", rStartTime);
+    logger->debug("findtimer: {}", timer->StopTime());
+    logger->debug("findtimer: {}", rStopTime);
+    logger->debug("findtimer: {}", timer->WeekDays());
+    logger->debug("findtimer: {}", rWeekDays);
+
+    if (
+            (strcmp(timer->Channel()->GetChannelID().ToString(), rChannelID) == 0)
+         && (strcmp(timer->File(), rName) == 0)
+         && (timer->StartTime() == atoi(rStartTime))
+         && (timer->StopTime() == atoi(rStopTime))
+         && (timer->WeekDays() == atoi(rWeekDays))
+       )
+    {
+      logger->debug("findtimer: found");
+      return timer;
+    }
+  }
+  logger->debug("findtimer: no timer found");
+  return NULL;
+}
+
+// Differs only from above by taking const Timers and returning const cTimer
+const cTimer* VDRClient::findTimer(const cTimers* Timers,
+                             const char* rChannelID, const char* rName, const char* rStartTime, const char* rStopTime, const char* rWeekDays)
+{
+  int numTimers = Timers->Count();
+  const cTimer* timer;
+  for (int i = 0; i < numTimers; i++)
+  {
+    timer = Timers->Get(i);
 
     logger->debug("findtimer: current: {}", (const char*)timer->ToText(true));
     logger->debug("findtimer: {}", (const char*)timer->Channel()->GetChannelID().ToString());
@@ -1646,14 +1677,14 @@ cTimer* VDRClient::findTimer(const char* rChannelID, const char* rName, const ch
   return NULL;
 }
 
-cTimer* VDRClient::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)
+cTimer* VDRClient::findTimer2(cTimers* Timers, 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)
 {
-  int numTimers = Timers.Count();
+  int numTimers = Timers->Count();
   cTimer* timer;
   logger->debug("findtimer2: {} {} {} {} {} {} {} {} {}", rName, rActive, rChannelID, rDay, rWeekDays, rStartTime, rStopTime, rPriority, rLifetime);
   for (int i = 0; i < numTimers; i++)
   {
-    timer = Timers.Get(i);
+    timer = Timers->Get(i);
 
     logger->debug("findtimer2: search: {} {} {} {} {} {} {} {} {}", timer->File(), timer->HasFlags(tfActive), (const char*)timer->Channel()->GetChannelID().ToString(),
                                                                                         (int)timer->Day(), timer->WeekDays(), (int)timer->StartTime(), (int)timer->StopTime(),
@@ -1684,7 +1715,7 @@ int VDRClient::getVarInt(PFMap& postFields, const char* paramName) // THROWS
   if (i == postFields.end()) throw BadParamException(paramName);
   int r;
   try { r = std::stoi(i->second); }
-  catch (std::exception e) { throw BadParamException(paramName); }
+  catch (const std::exception& e) { throw BadParamException(paramName); }
   return r;
 }
 
@@ -1739,7 +1770,7 @@ bool VDRClient::loadEpgFilter(libconfig::Config& epgFilter)
       return false;
     }
   }
-  catch (libconfig::SettingNotFoundException e)
+  catch (const libconfig::SettingNotFoundException& e)
   {
     libconfig::Setting& setting = epgFilter.getRoot();
     setting.add("filters", libconfig::Setting::Type::TypeList);
index 72f160a042ce9a1c662d727a20f51dd3f2dce397..0c2eb34c198dfaf942225a5c6132f354740fcb39 100644 (file)
@@ -12,6 +12,10 @@ namespace spd = spdlog;
 
 class cEvent;
 class cTimer;
+class cChannels;
+class cSchedules;
+class cTimers;
+class cRecordings;
 
 class VDRClient
 {
@@ -53,11 +57,17 @@ class VDRClient
     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);
-    const cEvent* getEvent(Json::Value& js, int channelNumber, int eventID, int aroundTime);
+    cTimer* findTimer(cTimers* Timers,
+                      const char* rChannelID, const char* rName, const char* rStartTime, const char* rStopTime, const char* rWeekDays);
+    const cTimer* findTimer(const cTimers* Timers,
+                      const char* rChannelID, const char* rName, const char* rStartTime, const char* rStopTime, const char* rWeekDays);
+    cTimer* findTimer2(cTimers* Timers,
+                       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);
+    const cEvent* getEvent(const cChannels* Channels, const cSchedules* Schedules,
+                           Json::Value& js, int channelNumber, int eventID, int aroundTime);
 
-    void pathsForRecordingName(const std::string& recordingName,
+    void pathsForRecordingName(const cRecordings* Recordings,
+                           const std::string& recordingName,
                            std::string& dirNameSingleDate,
                            std::string& dirNameSingleTitle,
                            std::string& dirNameSingleFolder,