summaryrefslogtreecommitdiff
path: root/searchtimer_thread.c
diff options
context:
space:
mode:
Diffstat (limited to 'searchtimer_thread.c')
-rw-r--r--searchtimer_thread.c1708
1 files changed, 812 insertions, 896 deletions
diff --git a/searchtimer_thread.c b/searchtimer_thread.c
index ba54566..a879487 100644
--- a/searchtimer_thread.c
+++ b/searchtimer_thread.c
@@ -58,996 +58,912 @@ cSearchResults cSearchTimerThread::announceList;
bool cSearchTimerThread::justRunning = false;
cSearchTimerThread::cSearchTimerThread(cPluginEpgsearch* thePlugin)
- : cThread("EPGSearch: searchtimer")
+ : cThread("EPGSearch: searchtimer")
{
- m_plugin = thePlugin;
- m_Active = false;
- m_lastUpdate = time(NULL);
+ m_plugin = thePlugin;
+ m_Active = false;
+ m_lastUpdate = time(NULL);
}
-cSearchTimerThread::~cSearchTimerThread() {
- if (m_Active)
- Stop();
+cSearchTimerThread::~cSearchTimerThread()
+{
+ if (m_Active)
+ Stop();
}
void cSearchTimerThread::Init(cPluginEpgsearch* thePlugin, bool activatePermanently)
{
- if (activatePermanently)
- {
- EPGSearchConfig.useSearchTimers = 1;
- thePlugin->SetupStore("UseSearchTimers", EPGSearchConfig.useSearchTimers);
- }
- if (!EPGSearchConfig.useSearchTimers)
- return;
- if (m_Instance == NULL) {
- m_Instance = new cSearchTimerThread(thePlugin);
- m_Instance->Start();
- }
+ if (activatePermanently) {
+ EPGSearchConfig.useSearchTimers = 1;
+ thePlugin->SetupStore("UseSearchTimers", EPGSearchConfig.useSearchTimers);
+ }
+ if (!EPGSearchConfig.useSearchTimers)
+ return;
+ if (m_Instance == NULL) {
+ m_Instance = new cSearchTimerThread(thePlugin);
+ m_Instance->Start();
+ }
}
-void cSearchTimerThread::Exit(void) {
- if (m_Instance != NULL) {
- m_Instance->Stop();
- DELETENULL(m_Instance);
- }
+void cSearchTimerThread::Exit(void)
+{
+ if (m_Instance != NULL) {
+ m_Instance->Stop();
+ DELETENULL(m_Instance);
+ }
}
-void cSearchTimerThread::Stop(void) {
- m_Active = false;
- Wait.Signal();
- Cancel(6);
+void cSearchTimerThread::Stop(void)
+{
+ m_Active = false;
+ Wait.Signal();
+ Cancel(6);
}
const cTimer *cSearchTimerThread::GetTimer(cSearchExt *searchExt, const cEvent *pEvent, bool& bTimesMatchExactly)
{
- LOCK_TIMERS_READ;
- LOCK_CHANNELS_READ;
- const cChannel *channel = Channels->GetByChannelID(pEvent->ChannelID(), true, true);
- if (!channel)
- return NULL;
-
- struct tm tm_r;
-
- bool UseVPS = searchExt->useVPS && pEvent->Vps() && Setup.UseVps;
- time_t eStart = pEvent->StartTime();
- time_t eStop = pEvent->EndTime();
- int eDuration = pEvent->Duration();
-
- int AllowedDiff = (eDuration < 10*60) ? (eDuration / 60): 10; // allowed start/stop difference
-
- int testVpsStart = 0;
- int testVpsStop = 0;
- time_t testVpsDay = 0;
- if (UseVPS)
- {
- eStart = pEvent->Vps();
- eStop = eStart + pEvent->Duration();
- cTimer VpsTestTimer(pEvent);
- testVpsStart = cTimer::TimeToInt(VpsTestTimer.Start());
- testVpsStop = cTimer::TimeToInt(VpsTestTimer.Stop());
- testVpsDay = VpsTestTimer.Day();
- }
-
- tm *tmStartEv = localtime_r(&eStart, &tm_r);
-
- for (const cTimer *ti = Timers->First(); ti; ti = Timers->Next(ti))
- {
- if (ti->Channel() != channel)
- continue;
-
- if (ti->WeekDays()) // ignore serial timers
- continue;
-
- if (ti->Remote()) // ignore remote timers
- continue;
- // ignore manual timers if this search could modify them
- if ((searchExt->action == searchTimerActionRecord || searchExt->action == searchTimerActionInactiveRecord) && TriggeredFromSearchTimerID(ti) == -1) // manual timer
- continue;
-
- if (UseVPS && ti->HasFlags(tfVps))
- {
- if (testVpsDay != ti->Day()) continue;
- int timerVpsStart = cTimer::TimeToInt(ti->Start());
- int timerVpsStop = cTimer::TimeToInt(ti->Stop());
-
- if (abs(testVpsStart - timerVpsStart) > AllowedDiff * 60) continue;
- if (abs(testVpsStop - timerVpsStop) > AllowedDiff * 60) continue;
-
- bTimesMatchExactly = (testVpsStart == timerVpsStart && testVpsStop == timerVpsStop);
- return ti;
- }
- else
- {
- time_t tStart = ti->StartTime() + searchExt->MarginStart * 60;
- time_t tStop = ti->StopTime() - searchExt->MarginStop * 60;
- tm *tmStartTi = localtime_r(&tStart, &tm_r);
- if (tmStartEv->tm_mday != tmStartTi->tm_mday)
+ LOCK_TIMERS_READ;
+ LOCK_CHANNELS_READ;
+ const cChannel *channel = Channels->GetByChannelID(pEvent->ChannelID(), true, true);
+ if (!channel)
+ return NULL;
+
+ struct tm tm_r;
+
+ bool UseVPS = searchExt->useVPS && pEvent->Vps() && Setup.UseVps;
+ time_t eStart = pEvent->StartTime();
+ time_t eStop = pEvent->EndTime();
+ int eDuration = pEvent->Duration();
+
+ int AllowedDiff = (eDuration < 10 * 60) ? (eDuration / 60) : 10; // allowed start/stop difference
+
+ int testVpsStart = 0;
+ int testVpsStop = 0;
+ time_t testVpsDay = 0;
+ if (UseVPS) {
+ eStart = pEvent->Vps();
+ eStop = eStart + pEvent->Duration();
+ cTimer VpsTestTimer(pEvent);
+ testVpsStart = cTimer::TimeToInt(VpsTestTimer.Start());
+ testVpsStop = cTimer::TimeToInt(VpsTestTimer.Stop());
+ testVpsDay = VpsTestTimer.Day();
+ }
+
+ tm *tmStartEv = localtime_r(&eStart, &tm_r);
+
+ for (const cTimer *ti = Timers->First(); ti; ti = Timers->Next(ti)) {
+ if (ti->Channel() != channel)
+ continue;
+
+ if (ti->WeekDays()) // ignore serial timers
continue;
- // some providers change EPG times only for a few seconds
- // ignore this to avoid search timer mails because of such changes
- bTimesMatchExactly = (abs(tStart -eStart) < 60 && abs(tStop - eStop) < 60);
+ if (ti->Remote()) // ignore remote timers
+ continue;
+ // ignore manual timers if this search could modify them
+ if ((searchExt->action == searchTimerActionRecord || searchExt->action == searchTimerActionInactiveRecord) && TriggeredFromSearchTimerID(ti) == -1) // manual timer
+ continue;
+
+ if (UseVPS && ti->HasFlags(tfVps)) {
+ if (testVpsDay != ti->Day()) continue;
+ int timerVpsStart = cTimer::TimeToInt(ti->Start());
+ int timerVpsStop = cTimer::TimeToInt(ti->Stop());
- if (abs(tStart - eStart) < AllowedDiff * 60 && abs(tStop - eStop) < AllowedDiff * 60) // accept a difference of max 10 min., but only if the event duration is more than 10 minutes
+ if (abs(testVpsStart - timerVpsStart) > AllowedDiff * 60) continue;
+ if (abs(testVpsStop - timerVpsStop) > AllowedDiff * 60) continue;
+
+ bTimesMatchExactly = (testVpsStart == timerVpsStart && testVpsStop == timerVpsStop);
return ti;
- }
- }
- return NULL;
+ } else {
+ time_t tStart = ti->StartTime() + searchExt->MarginStart * 60;
+ time_t tStop = ti->StopTime() - searchExt->MarginStop * 60;
+ tm *tmStartTi = localtime_r(&tStart, &tm_r);
+ if (tmStartEv->tm_mday != tmStartTi->tm_mday)
+ continue;
+
+ // some providers change EPG times only for a few seconds
+ // ignore this to avoid search timer mails because of such changes
+ bTimesMatchExactly = (abs(tStart - eStart) < 60 && abs(tStop - eStop) < 60);
+
+ if (abs(tStart - eStart) < AllowedDiff * 60 && abs(tStop - eStop) < AllowedDiff * 60) // accept a difference of max 10 min., but only if the event duration is more than 10 minutes
+ return ti;
+ }
+ }
+ return NULL;
}
bool cSearchTimerThread::TimerWasModified(const cTimer* t)
{
- if (!t) return false;
- if (t->HasFlags(tfVps)) return false; // if timer uses VPS we ignore user changes
-
- char* start = GetAuxValue(t, "start");
- char* stop = GetAuxValue(t, "stop");
- bool bMod = false;
- if (start || stop)
- {
- time_t StartTime = time_t(atol(start));
- time_t StopTime = time_t(atol(stop));
- if (abs(t->StartTime() - StartTime) >= 60 || abs(t->StopTime() -StopTime) >= 60)
- bMod = true;
- }
- if (start) free(start);
- if (stop) free(stop);
- return bMod;
+ if (!t) return false;
+ if (t->HasFlags(tfVps)) return false; // if timer uses VPS we ignore user changes
+
+ char* start = GetAuxValue(t, "start");
+ char* stop = GetAuxValue(t, "stop");
+ bool bMod = false;
+ if (start || stop) {
+ time_t StartTime = time_t(atol(start));
+ time_t StopTime = time_t(atol(stop));
+ if (abs(t->StartTime() - StartTime) >= 60 || abs(t->StopTime() - StopTime) >= 60)
+ bMod = true;
+ }
+ if (start) free(start);
+ if (stop) free(stop);
+ return bMod;
}
void cSearchTimerThread::Action(void)
{
- if (EPGSearchConfig.useExternalSVDRP && !epgsSVDRP::cSVDRPClient::SVDRPSendCmd)
- {
- LogFile.eSysLog("ERROR - SVDRPSend script not specified or does not exist (use -f option)");
- return;
- }
- SetPriority(SEARCHTIMER_NICE);
-
- m_Active = true;
- // let VDR do its startup
- if (!cPluginEpgsearch::VDR_readyafterStartup)
- LogFile.Log(2, "SearchTimerThread: waiting for VDR to become ready...");
- while(Running() && m_Active && !cPluginEpgsearch::VDR_readyafterStartup)
- Wait.Wait(1000);
-
- time_t nextUpdate = time(NULL);
- while (m_Active && Running())
- {
- time_t now = time(NULL);
- bool needUpdate = NeedUpdate();
- if (now >= nextUpdate || needUpdate)
- {
- justRunning = true;
-
- if (updateForced & UPDS_WITH_EPGSCAN)
- {
- LogFile.Log(1,"starting EPG scan before search timer update");
- EITScanner.ForceScan();
- do
- {
- Wait.Wait(1000);
- }
- while(EITScanner.Active() && m_Active && Running());
- LogFile.Log(1,"EPG scan finished");
- }
- // wait if TimersWriteLock is set or waited for
- {
- LOCK_TIMERS_WRITE;
- Timers->SetExplicitModify();
- }
- LogFile.iSysLog("search timer update started");
-
- UserVars.ResetCache(); // reset internal cache of user vars
- cTimerObjList* pOutdatedTimers = NULL;
-
- // for thread safeness we work with a copy of the current searches,
- // because SVDRP would not work if the main thread would be locked
- cSearchExts* localSearchExts = SearchExts.Clone();
- localSearchExts->SortBy(CompareSearchExtPrioDescTerm);
- cSearchExt *searchExt = localSearchExts->First();
- // reset announcelist
- announceList.Clear();
- while (searchExt && m_Active && Running())
- {
- if (!searchExt->IsActiveAt(now))
- {
- searchExt = localSearchExts->Next(searchExt);
- continue;
+ if (EPGSearchConfig.useExternalSVDRP && !epgsSVDRP::cSVDRPClient::SVDRPSendCmd) {
+ LogFile.eSysLog("ERROR - SVDRPSend script not specified or does not exist (use -f option)");
+ return;
+ }
+ SetPriority(SEARCHTIMER_NICE);
+
+ m_Active = true;
+ // let VDR do its startup
+ if (!cPluginEpgsearch::VDR_readyafterStartup)
+ LogFile.Log(2, "SearchTimerThread: waiting for VDR to become ready...");
+ while (Running() && m_Active && !cPluginEpgsearch::VDR_readyafterStartup)
+ Wait.Wait(1000);
+
+ time_t nextUpdate = time(NULL);
+ while (m_Active && Running()) {
+ time_t now = time(NULL);
+ bool needUpdate = NeedUpdate();
+ if (now >= nextUpdate || needUpdate) {
+ justRunning = true;
+
+ if (updateForced & UPDS_WITH_EPGSCAN) {
+ LogFile.Log(1, "starting EPG scan before search timer update");
+ EITScanner.ForceScan();
+ do {
+ Wait.Wait(1000);
+ } while (EITScanner.Active() && m_Active && Running());
+ LogFile.Log(1, "EPG scan finished");
}
- pOutdatedTimers = searchExt->GetTimerList(pOutdatedTimers);
-
- cSearchResults* pSearchResults = searchExt->Run(-1, true);
- if (!pSearchResults)
+ // wait if TimersWriteLock is set or waited for
{
- searchExt = localSearchExts->Next(searchExt);
- continue;
+ LOCK_TIMERS_WRITE;
+ Timers->SetExplicitModify();
+ }
+ LogFile.iSysLog("search timer update started");
+
+ UserVars.ResetCache(); // reset internal cache of user vars
+ cTimerObjList* pOutdatedTimers = NULL;
+
+ // for thread safeness we work with a copy of the current searches,
+ // because SVDRP would not work if the main thread would be locked
+ cSearchExts* localSearchExts = SearchExts.Clone();
+ localSearchExts->SortBy(CompareSearchExtPrioDescTerm);
+ cSearchExt *searchExt = localSearchExts->First();
+ // reset announcelist
+ announceList.Clear();
+ while (searchExt && m_Active && Running()) {
+ if (!searchExt->IsActiveAt(now)) {
+ searchExt = localSearchExts->Next(searchExt);
+ continue;
+ }
+ pOutdatedTimers = searchExt->GetTimerList(pOutdatedTimers);
+
+ cSearchResults* pSearchResults = searchExt->Run(-1, true);
+ if (!pSearchResults) {
+ searchExt = localSearchExts->Next(searchExt);
+ continue;
+ }
+ pSearchResults->SortBy(CompareEventTime);
+
+ if (searchExt->pauseOnNrRecordings > 0)
+ searchExt->CheckExistingRecordings(pSearchResults);
+
+ for (cSearchResult* pResultObj = pSearchResults->First();
+ pResultObj;
+ pResultObj = pSearchResults->Next(pResultObj)) {
+ if (!Running()) break;
+ const cEvent* pEvent = pResultObj->event;
+ if (!pEvent)
+ continue;
+
+ {
+ LOCK_CHANNELS_READ;
+ const cChannel *channel = Channels->GetByChannelID(pEvent->ChannelID(), true, true);
+ if (!channel)
+ continue;
+ }
+
+ int index = 0;
+ cTimer *timer = new cTimer(pEvent);
+
+ // create the file
+ char* file = NULL;
+ if ((file = searchExt->BuildFile(pEvent)) != NULL) {
+ while (strstr(file, "!^pipe^!")) file = strreplace(file, "!^pipe^!", "|"); // revert the translation of '|' in BuildFile
+ if (strstr(file, "!^invalid^!") || strlen(file) == 0) {
+ LogFile.eSysLog("Skipping timer due to invalid or empty filename");
+ if (time(NULL) <= timer->StopTime())
+ pOutdatedTimers->DelTimer(timer);
+ delete timer;
+ free(file);
+ continue;
+ }
+ timer->SetFile(file);
+ free(file);
+ }
+ int Priority = searchExt->Priority;
+ int Lifetime = searchExt->Lifetime;
+
+ // search for an already existing timer
+ bool bTimesMatchExactly = false;
+ const cTimer *t = GetTimer(searchExt, pEvent, bTimesMatchExactly);
+
+ char* Summary = NULL;
+ uint timerMod = tmNoChange;
+
+ if (t) {
+ // already exists
+ pOutdatedTimers->DelTimer(t);
+
+ if (!t->HasFlags(tfActive)) {
+ // do not update inactive timers
+ LogFile.Log(2, "timer for '%s~%s' (%s - %s, channel %d) not active - won't be touched", pEvent->Title() ? pEvent->Title() : "no title", pEvent->ShortText() ? pEvent->ShortText() : "no subtitle", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), ChannelNrFromEvent(pEvent));
+ delete timer;
+ continue;
+ }
+
+ int triggerID = TriggeredFromSearchTimerID(t);
+ if (!pResultObj->needsTimer && !t->Recording()) { // not needed
+ if (triggerID == searchExt->ID) {
+ LogFile.Log(1, "delete timer for '%s~%s' (%s - %s, channel %d)", pEvent->Title() ? pEvent->Title() : "no title", pEvent->ShortText() ? pEvent->ShortText() : "no subtitle", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), ChannelNrFromEvent(pEvent));
+ RemoveTimer(t, pEvent);
+ } else if (triggerID == -1) { //manual timer
+ LogFile.Log(2, "keep obsolete timer for '%s~%s' (%s - %s, channel %d) - was manually created", pEvent->Title() ? pEvent->Title() : "no title", pEvent->ShortText() ? pEvent->ShortText() : "no subtitle", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), ChannelNrFromEvent(pEvent));
+ }
+ delete timer;
+ continue;
+ }
+ if (TimerWasModified(t)) { // don't touch timer modified by user
+ LogFile.Log(2, "timer for '%s~%s' (%s - %s, channel %d) modified by user - won't be touched", pEvent->Title() ? pEvent->Title() : "no title", pEvent->ShortText() ? pEvent->ShortText() : "no subtitle", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), ChannelNrFromEvent(pEvent));
+ delete timer;
+ continue;
+ }
+ if (triggerID > -1 && triggerID != searchExt->ID) {
+ LogFile.Log(2, "timer for '%s~%s' (%s - %s, channel %d) already created by search id %d - won't be touched", pEvent->Title() ? pEvent->Title() : "no title", pEvent->ShortText() ? pEvent->ShortText() : "no subtitle", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), ChannelNrFromEvent(pEvent), triggerID);
+ delete timer;
+ continue;
+ }
+
+ char* pFile = NULL; // File is prepared for svdrp, so prepare t->File for comparison too
+ msprintf(&pFile, "%s", t->File());
+ pFile = strreplace(pFile, ':', '|');
+ pFile = strreplace(pFile, " ~", "~");
+ pFile = strreplace(pFile, "~ ", "~");
+
+ Summary = SummaryExtended(searchExt, t, pEvent);
+
+ if (bTimesMatchExactly && strcmp(pFile, timer->File()) == 0
+ && (t->Aux() != NULL && strcmp(t->Aux(), Summary) == 0)
+ ) {
+ // dir, title, episode name and summary have not changed
+ if (Summary) free(Summary);
+ delete timer;
+ free(pFile);
+ continue;
+ } else {
+ if (!bTimesMatchExactly) timerMod = (uint)timerMod | tmStartStop;
+ if (strcmp(pFile, timer->File()) != 0) timerMod |= tmFile;
+ if (t->Aux() != NULL && strcmp(t->Aux(), Summary) != 0) {
+ char* oldEventID = GetAuxValue(t, "eventid");
+ char* newEventID = GetAuxValue(Summary, "eventid");
+ if (oldEventID && newEventID && strcmp(oldEventID, newEventID) != 0)
+ timerMod |= tmAuxEventID;
+ free(oldEventID);
+ free(newEventID);
+ }
+
+ if (LogFile.Level() >= 3) { // output reasons for a timer modification
+ if (timerMod & tmStartStop)
+ LogFile.Log(3, "timer for '%s~%s' (%s - %s, channel %d) : start/stop has changed", pEvent->Title() ? pEvent->Title() : "no title", pEvent->ShortText() ? pEvent->ShortText() : "no subtitle", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), ChannelNrFromEvent(pEvent));
+ if (timerMod & tmFile)
+ LogFile.Log(3, "timer for '%s~%s' (%s - %s, channel %d) : title and/or episdode has changed (old: %s, new: %s", pEvent->Title() ? pEvent->Title() : "no title", pEvent->ShortText() ? pEvent->ShortText() : "no subtitle", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), ChannelNrFromEvent(pEvent), timer ? timer->File() : "", pFile);
+ if (timerMod & tmAuxEventID)
+ LogFile.Log(3, "timer for '%s~%s' (%s - %s, channel %d) : aux info for event id has changed", pEvent->Title() ? pEvent->Title() : "no title", pEvent->ShortText() ? pEvent->ShortText() : "no subtitle", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), ChannelNrFromEvent(pEvent));
+ }
+ index = t->Id();
+ Priority = t->Priority();
+ Lifetime = t->Lifetime();
+ }
+ free(pFile);
+
+ if (t->Recording() && t->StopTime() == timer->StopTime()) {
+ // only update recording timers if stop time has changed, since all other settings can't be modified
+ LogFile.Log(2, "timer for '%s~%s' (%s - %s, channel %d) already recording - no changes possible", pEvent->Title() ? pEvent->Title() : "no title", pEvent->ShortText() ? pEvent->ShortText() : "no subtitle", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), ChannelNrFromEvent(pEvent));
+ delete timer;
+ continue;
+ }
+ } else {
+ if (!pResultObj->needsTimer) {
+ delete timer;
+ continue;
+ }
+ }
+
+ if (searchExt->action == searchTimerActionAnnounceViaOSD) {
+ if (t || // timer already exists or
+ NoAnnounces.InList(pEvent) || // announcement not wanted anymore or
+ (EPGSearchConfig.noAnnounceWhileReplay &&
+ cDevice::PrimaryDevice()->Replaying() &&
+ !(updateForced & UPDS_WITH_OSD)) // no announce while replay within automatic updates
+ ) {
+ if (Summary) free(Summary);
+ delete timer;
+ continue;
+ }
+ if (!announceList.Lookup(pEvent))
+ announceList.Add(new cSearchResult(pEvent, searchExt->ID));
+
+ if (Summary) free(Summary);
+ delete timer;
+ continue;
+ }
+
+ if (searchExt->action == searchTimerActionAnnounceViaMail) {
+ if (t || // timer already exists or
+ NoAnnounces.InList(pEvent) ||
+ pEvent->StartTime() < time(NULL)) { // already started?
+ if (Summary) free(Summary);
+ delete timer;
+ continue;
+ }
+ mailNotifier.AddAnnounceEventNotification(pEvent->EventID(), pEvent->ChannelID(), searchExt->ID);
+
+ if (Summary) free(Summary);
+ delete timer;
+ continue;
+ }
+ if (searchExt->action == searchTimerActionSwitchOnly ||
+ searchExt->action == searchTimerActionAnnounceAndSwitch) { // add to switch list
+ time_t now = time(NULL);
+ if (now < pEvent->StartTime()) {
+ if (!SwitchTimers.InSwitchList(pEvent)) {
+ cMutexLock SwitchTimersLock(&SwitchTimers);
+ int mode = 0;
+ if (searchExt->action == searchTimerActionAnnounceAndSwitch)
+ mode = 2;
+ LogFile.Log(3, "adding switch timer event for '%s~%s' (%s - %s); search timer: '%s'", pEvent->Title(), pEvent->ShortText() ? pEvent->ShortText() : "", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), searchExt->search);
+ SwitchTimers.Add(new cSwitchTimer(pEvent, searchExt->switchMinsBefore, mode,
+ searchExt->unmuteSoundOnSwitch));
+ SwitchTimers.Save();
+ cSwitchTimerThread::Init();
+ }
+ }
+ if (Summary) free(Summary);
+ delete timer;
+ continue;
+ }
+
+ if (AddModTimer(timer, index, searchExt, pEvent, Priority, Lifetime, Summary, timerMod)) {
+ if (index == 0)
+ LogFile.Log(1, "added timer for '%s~%s' (%s - %s); search timer: '%s'", pEvent->Title(), pEvent->ShortText() ? pEvent->ShortText() : "", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), searchExt->search);
+ else
+ LogFile.Log(1, "modified timer %d for '%s~%s' (%s - %s); search timer: '%s'", index, pEvent->Title(), pEvent->ShortText() ? pEvent->ShortText() : "", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), searchExt->search);
+ }
+ if (Summary) free(Summary);
+ delete timer;
+ }
+ delete pSearchResults;
+ searchExt = localSearchExts->Next(searchExt);
}
- pSearchResults->SortBy(CompareEventTime);
-
- if (searchExt->pauseOnNrRecordings > 0)
- searchExt->CheckExistingRecordings(pSearchResults);
- for (cSearchResult* pResultObj = pSearchResults->First();
- pResultObj;
- pResultObj = pSearchResults->Next(pResultObj))
- {
- if (!Running()) break;
- const cEvent* pEvent = pResultObj->event;
- if (!pEvent)
- continue;
-
- {
- LOCK_CHANNELS_READ;
- const cChannel *channel = Channels->GetByChannelID(pEvent->ChannelID(), true, true);
- if (!channel)
- continue;
- }
-
- int index = 0;
- cTimer *timer = new cTimer(pEvent);
-
- // create the file
- char* file = NULL;
- if ((file = searchExt->BuildFile(pEvent)) != NULL)
- {
- while(strstr(file, "!^pipe^!")) file = strreplace(file, "!^pipe^!", "|"); // revert the translation of '|' in BuildFile
- if (strstr(file, "!^invalid^!") || strlen(file) == 0)
- {
- LogFile.eSysLog("Skipping timer due to invalid or empty filename");
- if (time(NULL) <= timer->StopTime())
- pOutdatedTimers->DelTimer(timer);
- delete timer;
- free(file);
- continue;
- }
- timer->SetFile(file);
- free(file);
- }
- int Priority = searchExt->Priority;
- int Lifetime = searchExt->Lifetime;
-
- // search for an already existing timer
- bool bTimesMatchExactly = false;
- const cTimer *t = GetTimer(searchExt, pEvent, bTimesMatchExactly);
-
- char* Summary = NULL;
- uint timerMod = tmNoChange;
-
- if (t)
- { // already exists
- pOutdatedTimers->DelTimer(t);
-
- if (!t->HasFlags(tfActive))
- { // do not update inactive timers
- LogFile.Log(2,"timer for '%s~%s' (%s - %s, channel %d) not active - won't be touched", pEvent->Title()?pEvent->Title():"no title", pEvent->ShortText()?pEvent->ShortText():"no subtitle", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), ChannelNrFromEvent(pEvent));
- delete timer;
- continue;
- }
-
- int triggerID = TriggeredFromSearchTimerID(t);
- if (!pResultObj->needsTimer && !t->Recording()) // not needed
- {
- if (triggerID == searchExt->ID)
- {
- LogFile.Log(1,"delete timer for '%s~%s' (%s - %s, channel %d)", pEvent->Title()?pEvent->Title():"no title", pEvent->ShortText()?pEvent->ShortText():"no subtitle", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), ChannelNrFromEvent(pEvent));
- RemoveTimer(t, pEvent);
- }
- else if (triggerID == -1) //manual timer
- {
- LogFile.Log(2,"keep obsolete timer for '%s~%s' (%s - %s, channel %d) - was manually created", pEvent->Title()?pEvent->Title():"no title", pEvent->ShortText()?pEvent->ShortText():"no subtitle", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), ChannelNrFromEvent(pEvent));
- }
- delete timer;
- continue;
- }
- if (TimerWasModified(t)) // don't touch timer modified by user
- {
- LogFile.Log(2,"timer for '%s~%s' (%s - %s, channel %d) modified by user - won't be touched", pEvent->Title()?pEvent->Title():"no title", pEvent->ShortText()?pEvent->ShortText():"no subtitle", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), ChannelNrFromEvent(pEvent));
- delete timer;
- continue;
- }
- if (triggerID > -1 && triggerID != searchExt->ID)
- {
- LogFile.Log(2,"timer for '%s~%s' (%s - %s, channel %d) already created by search id %d - won't be touched", pEvent->Title()?pEvent->Title():"no title", pEvent->ShortText()?pEvent->ShortText():"no subtitle", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), ChannelNrFromEvent(pEvent), triggerID);
- delete timer;
- continue;
- }
-
- char* pFile = NULL; // File is prepared for svdrp, so prepare t->File for comparison too
- msprintf(&pFile, "%s", t->File());
- pFile = strreplace(pFile, ':', '|');
- pFile = strreplace(pFile, " ~", "~");
- pFile = strreplace(pFile, "~ ", "~");
-
- Summary = SummaryExtended(searchExt, t, pEvent);
-
- if (bTimesMatchExactly && strcmp(pFile, timer->File()) == 0
- && (t->Aux() != NULL && strcmp(t->Aux(), Summary) == 0)
- )
- { // dir, title, episode name and summary have not changed
- if (Summary) free(Summary);
- delete timer;
- free(pFile);
- continue;
- }
- else
- {
- if (!bTimesMatchExactly) timerMod = (uint)timerMod | tmStartStop;
- if (strcmp(pFile, timer->File()) != 0) timerMod |= tmFile;
- if (t->Aux() != NULL && strcmp(t->Aux(), Summary) != 0)
- {
- char* oldEventID = GetAuxValue(t, "eventid");
- char* newEventID = GetAuxValue(Summary, "eventid");
- if (oldEventID && newEventID && strcmp(oldEventID, newEventID) != 0)
- timerMod |= tmAuxEventID;
- free(oldEventID);
- free(newEventID);
- }
-
- if (LogFile.Level() >= 3) // output reasons for a timer modification
- {
- if (timerMod & tmStartStop)
- LogFile.Log(3,"timer for '%s~%s' (%s - %s, channel %d) : start/stop has changed", pEvent->Title()?pEvent->Title():"no title", pEvent->ShortText()?pEvent->ShortText():"no subtitle", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), ChannelNrFromEvent(pEvent));
- if (timerMod & tmFile)
- LogFile.Log(3,"timer for '%s~%s' (%s - %s, channel %d) : title and/or episdode has changed (old: %s, new: %s", pEvent->Title()?pEvent->Title():"no title", pEvent->ShortText()?pEvent->ShortText():"no subtitle", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), ChannelNrFromEvent(pEvent), timer?timer->File():"", pFile);
- if (timerMod & tmAuxEventID)
- LogFile.Log(3,"timer for '%s~%s' (%s - %s, channel %d) : aux info for event id has changed", pEvent->Title()?pEvent->Title():"no title", pEvent->ShortText()?pEvent->ShortText():"no subtitle", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), ChannelNrFromEvent(pEvent));
- }
- index = t->Id();
- Priority = t->Priority();
- Lifetime = t->Lifetime();
- }
- free(pFile);
-
- if (t->Recording() && t->StopTime() == timer->StopTime())
- {
- // only update recording timers if stop time has changed, since all other settings can't be modified
- LogFile.Log(2,"timer for '%s~%s' (%s - %s, channel %d) already recording - no changes possible", pEvent->Title()?pEvent->Title():"no title", pEvent->ShortText()?pEvent->ShortText():"no subtitle", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), ChannelNrFromEvent(pEvent));
- delete timer;
- continue;
- }
- }
- else
- {
- if (!pResultObj->needsTimer)
- {
- delete timer;
- continue;
- }
- }
-
- if (searchExt->action == searchTimerActionAnnounceViaOSD)
- {
- if (t || // timer already exists or
- NoAnnounces.InList(pEvent) || // announcement not wanted anymore or
- (EPGSearchConfig.noAnnounceWhileReplay &&
- cDevice::PrimaryDevice()->Replaying() &&
- !(updateForced & UPDS_WITH_OSD)) // no announce while replay within automatic updates
- )
- {
- if (Summary) free(Summary);
- delete timer;
- continue;
- }
- if (!announceList.Lookup(pEvent))
- announceList.Add(new cSearchResult(pEvent, searchExt->ID));
-
- if (Summary) free(Summary);
- delete timer;
- continue;
- }
-
- if (searchExt->action == searchTimerActionAnnounceViaMail)
- {
- if (t || // timer already exists or
- NoAnnounces.InList(pEvent) ||
- pEvent->StartTime() < time(NULL)) // already started?
- {
- if (Summary) free(Summary);
- delete timer;
- continue;
- }
- mailNotifier.AddAnnounceEventNotification(pEvent->EventID(), pEvent->ChannelID(), searchExt->ID);
-
- if (Summary) free(Summary);
- delete timer;
- continue;
- }
- if (searchExt->action == searchTimerActionSwitchOnly ||
- searchExt->action == searchTimerActionAnnounceAndSwitch) // add to switch list
- {
- time_t now = time(NULL);
- if (now < pEvent->StartTime())
- {
- if (!SwitchTimers.InSwitchList(pEvent))
- {
- cMutexLock SwitchTimersLock(&SwitchTimers);
- int mode = 0;
- if (searchExt->action == searchTimerActionAnnounceAndSwitch)
- mode = 2;
- LogFile.Log(3,"adding switch timer event for '%s~%s' (%s - %s); search timer: '%s'", pEvent->Title(), pEvent->ShortText()?pEvent->ShortText():"", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), searchExt->search);
- SwitchTimers.Add(new cSwitchTimer(pEvent, searchExt->switchMinsBefore, mode,
- searchExt->unmuteSoundOnSwitch));
- SwitchTimers.Save();
- cSwitchTimerThread::Init();
- }
- }
- if (Summary) free(Summary);
- delete timer;
- continue;
- }
-
- if (AddModTimer(timer, index, searchExt, pEvent, Priority, Lifetime, Summary, timerMod))
- {
- if (index == 0)
- LogFile.Log(1,"added timer for '%s~%s' (%s - %s); search timer: '%s'", pEvent->Title(), pEvent->ShortText()?pEvent->ShortText():"", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), searchExt->search);
- else
- LogFile.Log(1,"modified timer %d for '%s~%s' (%s - %s); search timer: '%s'", index, pEvent->Title(), pEvent->ShortText()?pEvent->ShortText():"", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), searchExt->search);
- }
- if (Summary) free(Summary);
- delete timer;
+ if (localSearchExts) delete localSearchExts;
+
+ if (pOutdatedTimers) {
+ if (pOutdatedTimers->Count() > 0) {
+ LogFile.Log(1, "removing outdated timers");
+ for (cTimerObj *tObj = pOutdatedTimers->First(); tObj; tObj = pOutdatedTimers->Next(tObj)) {
+ const cTimer* t = tObj->timer;
+ // timer could have been deleted meanwhile, so check if its still there
+ {
+ LOCK_TIMERS_READ;
+ if (!Timers->Contains(t))
+ continue;
+ }
+
+ if (TimerWasModified(t)) continue;
+ if (!t->Event()) continue; // if there is no event, we keep the timer, since EPG could have been cleared
+ if (time(NULL) > t->StopTime()) continue; // if this timer has (just) finished, let VDR do the cleanup
+ if (t->Recording()) continue; // do not remove recording timers
+ LogFile.Log(1, "delete timer for '%s' (%s, channel %s)", t->File(), DAYDATETIME(t->StartTime()), CHANNELNAME(t->Channel()));
+ RemoveTimer(t, t->Event());
+ }
+ LogFile.Log(1, "removing outdated timers - done");
+ }
+ delete pOutdatedTimers;
}
- delete pSearchResults;
- searchExt = localSearchExts->Next(searchExt);
- }
- if (localSearchExts) delete localSearchExts;
+ TimersDone.ClearOutdated();
+ TimersDone.Save();
- if (pOutdatedTimers)
- {
- if (pOutdatedTimers->Count() > 0)
- {
- LogFile.Log(1,"removing outdated timers");
- for(cTimerObj *tObj = pOutdatedTimers->First(); tObj; tObj = pOutdatedTimers->Next(tObj))
- {
- const cTimer* t = tObj->timer;
- // timer could have been deleted meanwhile, so check if its still there
- {
- LOCK_TIMERS_READ;
- if (!Timers->Contains(t))
- continue;
- }
-
- if (TimerWasModified(t)) continue;
- if (!t->Event()) continue; // if there is no event, we keep the timer, since EPG could have been cleared
- if (time(NULL) > t->StopTime()) continue; // if this timer has (just) finished, let VDR do the cleanup
- if (t->Recording()) continue; // do not remove recording timers
- LogFile.Log(1,"delete timer for '%s' (%s, channel %s)", t->File(), DAYDATETIME(t->StartTime()), CHANNELNAME(t->Channel()));
- RemoveTimer(t, t->Event());
- }
- LogFile.Log(1,"removing outdated timers - done");
- }
- delete pOutdatedTimers;
- }
-
- TimersDone.ClearOutdated();
- TimersDone.Save();
-
- if (announceList.Count() > 0)
- {
- cString msgfmt = cString::sprintf(tr("%d new broadcast(s) found! Show them?"), announceList.Count());
- if (SendMsg(msgfmt, true, 7) == kOk)
- {
- m_plugin->showAnnounces = true;
- cRemote::CallPlugin("epgsearch");
- }
- }
-
- CheckEPGHours();
-
- LogFile.iSysLog("search timer update finished");
-
- // check for conflicts
- if (EPGSearchConfig.checkTimerConflictsAfterUpdate && m_Active && Running())
- {
- LogFile.iSysLog("check for timer conflicts");
- cConflictCheck conflictCheck;
- conflictCheck.Check();
-
- if (conflictCheck.relevantConflicts > 0)
- {
- if (EPGSearchConfig.sendMailOnConflicts)
- {
- cMailConflictNotifier mailNotifier;
- mailNotifier.SendConflictNotifications(conflictCheck);
- }
-
- conflictCheck.EvaluateConflCheckCmd();
-
- cString msgfmt = "";
- if (conflictCheck.relevantConflicts == 1)
- msgfmt = cString::sprintf(tr("timer conflict at %s! Show it?"),
- *DateTime(conflictCheck.nextRelevantConflictDate));
- else
- msgfmt = cString::sprintf(tr("%d timer conflicts! First at %s. Show them?"),
- conflictCheck.relevantConflicts,
- *DateTime(conflictCheck.nextRelevantConflictDate));
-
- bool doMessage = EPGSearchConfig.noConflMsgWhileReplay == 0 ||
- !cDevice::PrimaryDevice()->Replaying() ||
- conflictCheck.nextRelevantConflictDate - now < 2*60*60 ||
- (updateForced & UPDS_WITH_OSD);
- if (doMessage && SendMsg(msgfmt, true,7,mtWarning) == kOk)
- {
- m_plugin->showConflicts = true;
- cRemote::CallPlugin("epgsearch");
- }
+ if (announceList.Count() > 0) {
+ cString msgfmt = cString::sprintf(tr("%d new broadcast(s) found! Show them?"), announceList.Count());
+ if (SendMsg(msgfmt, true, 7) == kOk) {
+ m_plugin->showAnnounces = true;
+ cRemote::CallPlugin("epgsearch");
+ }
}
- LogFile.iSysLog("check for timer conflicts - done");
- }
+ CheckEPGHours();
+
+ LogFile.iSysLog("search timer update finished");
+
+ // check for conflicts
+ if (EPGSearchConfig.checkTimerConflictsAfterUpdate && m_Active && Running()) {
+ LogFile.iSysLog("check for timer conflicts");
+ cConflictCheck conflictCheck;
+ conflictCheck.Check();
+
+ if (conflictCheck.relevantConflicts > 0) {
+ if (EPGSearchConfig.sendMailOnConflicts) {
+ cMailConflictNotifier mailNotifier;
+ mailNotifier.SendConflictNotifications(conflictCheck);
+ }
+
+ conflictCheck.EvaluateConflCheckCmd();
+
+ cString msgfmt = "";
+ if (conflictCheck.relevantConflicts == 1)
+ msgfmt = cString::sprintf(tr("timer conflict at %s! Show it?"),
+ *DateTime(conflictCheck.nextRelevantConflictDate));
+ else
+ msgfmt = cString::sprintf(tr("%d timer conflicts! First at %s. Show them?"),
+ conflictCheck.relevantConflicts,
+ *DateTime(conflictCheck.nextRelevantConflictDate));
+
+ bool doMessage = EPGSearchConfig.noConflMsgWhileReplay == 0 ||
+ !cDevice::PrimaryDevice()->Replaying() ||
+ conflictCheck.nextRelevantConflictDate - now < 2 * 60 * 60 ||
+ (updateForced & UPDS_WITH_OSD);
+ if (doMessage && SendMsg(msgfmt, true, 7, mtWarning) == kOk) {
+ m_plugin->showConflicts = true;
+ cRemote::CallPlugin("epgsearch");
+ }
+ }
+
+ LogFile.iSysLog("check for timer conflicts - done");
+ }
- // delete expired recordings
- CheckExpiredRecs();
+ // delete expired recordings
+ CheckExpiredRecs();
- // check for updates for manual timers
- CheckManualTimers();
+ // check for updates for manual timers
+ CheckManualTimers();
- if (m_Active)
- mailNotifier.SendUpdateNotifications();
+ if (m_Active)
+ mailNotifier.SendUpdateNotifications();
- if ((updateForced & UPDS_WITH_OSD) && m_Active)
- SendMsg(tr("Search timer update done!"));
+ if ((updateForced & UPDS_WITH_OSD) && m_Active)
+ SendMsg(tr("Search timer update done!"));
- // reset service call flag
- updateForced = 0;
+ // reset service call flag
+ updateForced = 0;
- m_lastUpdate = time(NULL);
- nextUpdate = long(m_lastUpdate/60)*60 + (EPGSearchConfig.UpdateIntervall * 60);
- justRunning = false;
- }
- if (m_Active && Running())
- Wait.Wait(2000); // to avoid high system load if time%30==0
- while (Running() && m_Active && !NeedUpdate() && time(NULL)%30 != 0) // sync heart beat to a multiple of 5secs
- Wait.Wait(1000);
- };
- LogFile.iSysLog("Leaving search timer thread");
+ m_lastUpdate = time(NULL);
+ nextUpdate = long(m_lastUpdate / 60) * 60 + (EPGSearchConfig.UpdateIntervall * 60);
+ justRunning = false;
+ }
+ if (m_Active && Running())
+ Wait.Wait(2000); // to avoid high system load if time%30==0
+ while (Running() && m_Active && !NeedUpdate() && time(NULL) % 30 != 0) // sync heart beat to a multiple of 5secs
+ Wait.Wait(1000);
+ };
+ LogFile.iSysLog("Leaving search timer thread");
}
bool cSearchTimerThread::NeedUpdate()
{
- return (m_lastUpdate <= LastModifiedTime(AddDirectory(CONFIGDIR, ".epgsearchupdate")) || updateForced>0);
+ return (m_lastUpdate <= LastModifiedTime(AddDirectory(CONFIGDIR, ".epgsearchupdate")) || updateForced > 0);
}
char* cSearchTimerThread::SummaryExtended(cSearchExt* searchExt, const cTimer* Timer, const cEvent* pEvent)
{
- bool UseVPS = searchExt->useVPS && pEvent->Vps() && Setup.UseVps;
- time_t eStart;
- if (!UseVPS)
- eStart = pEvent->StartTime();
- else
- eStart = pEvent->Vps();
- time_t eStop;
- if (!UseVPS)
- eStop = pEvent->EndTime();
- else
- eStop = pEvent->Vps() + pEvent->Duration();
- // make sure that eStart and eStop represent a full minute
- eStart = (eStart / 60) * 60;
- eStop = (eStop / 60) * 60;
-
- time_t start = eStart - (UseVPS?0:(searchExt->MarginStart * 60));
- time_t stop = eStop + (UseVPS?0:(searchExt->MarginStop * 60));
-
- char* addSummaryFooter = NULL;
- msprintf(&addSummaryFooter, "<channel>%d - %s</channel><searchtimer>%s</searchtimer><start>%ld</start><stop>%ld</stop><s-id>%d</s-id><eventid>%ld</eventid>",
- Timer->Channel()->Number(), CHANNELNAME(Timer->Channel()),
- searchExt->search,
- start,
- stop,
- searchExt->ID,
- (long) pEvent->EventID());
-
- const char* aux = Timer->Aux();
- // remove epgsearch entries
- char* tmpaux = NULL;
- if (!isempty(aux))
- {
- tmpaux = strdup(aux);
- const char* begin = strstr(aux, "<epgsearch>");
- const char* end = strstr(aux, "</epgsearch>");
- if (begin && end)
- {
- if (begin == aux) strcpy(tmpaux, ""); else strn0cpy(tmpaux, aux, begin-aux+1);
- strcat(tmpaux, end + strlen("</epgsearch>"));
- }
- }
-
- char* tmpSummary = NULL;
- msprintf(&tmpSummary, "<epgsearch>%s</epgsearch>%s", addSummaryFooter, tmpaux?tmpaux:"");
- free(addSummaryFooter);
- if (tmpaux) free(tmpaux);
- return tmpSummary;
+ bool UseVPS = searchExt->useVPS && pEvent->Vps() && Setup.UseVps;
+ time_t eStart;
+ if (!UseVPS)
+ eStart = pEvent->StartTime();
+ else
+ eStart = pEvent->Vps();
+ time_t eStop;
+ if (!UseVPS)
+ eStop = pEvent->EndTime();
+ else
+ eStop = pEvent->Vps() + pEvent->Duration();
+ // make sure that eStart and eStop represent a full minute
+ eStart = (eStart / 60) * 60;
+ eStop = (eStop / 60) * 60;
+
+ time_t start = eStart - (UseVPS ? 0 : (searchExt->MarginStart * 60));
+ time_t stop = eStop + (UseVPS ? 0 : (searchExt->MarginStop * 60));
+
+ char* addSummaryFooter = NULL;
+ msprintf(&addSummaryFooter, "<channel>%d - %s</channel><searchtimer>%s</searchtimer><start>%ld</start><stop>%ld</stop><s-id>%d</s-id><eventid>%ld</eventid>",
+ Timer->Channel()->Number(), CHANNELNAME(Timer->Channel()),
+ searchExt->search,
+ start,
+ stop,
+ searchExt->ID,
+ (long) pEvent->EventID());
+
+ const char* aux = Timer->Aux();
+ // remove epgsearch entries
+ char* tmpaux = NULL;
+ if (!isempty(aux)) {
+ tmpaux = strdup(aux);
+ const char* begin = strstr(aux, "<epgsearch>");
+ const char* end = strstr(aux, "</epgsearch>");
+ if (begin && end) {
+ if (begin == aux) strcpy(tmpaux, "");
+ else strn0cpy(tmpaux, aux, begin - aux + 1);
+ strcat(tmpaux, end + strlen("</epgsearch>"));
+ }
+ }
+
+ char* tmpSummary = NULL;
+ msprintf(&tmpSummary, "<epgsearch>%s</epgsearch>%s", addSummaryFooter, tmpaux ? tmpaux : "");
+ free(addSummaryFooter);
+ if (tmpaux) free(tmpaux);
+ return tmpSummary;
}
bool cSearchTimerThread::AddModTimer(cTimer* Timer, int index, cSearchExt* searchExt, const cEvent* pEvent, int Prio, int Lifetime, char* Summary, uint timerMod)
{
- char *cmdbuf = NULL;
-
- static char bufStart[25];
- static char bufEnd[25];
-
- struct tm tm_r; time_t eStart = pEvent->StartTime();
- time_t eStop = pEvent->EndTime();
- time_t start = eStart - (searchExt->MarginStart * 60);
- time_t stop = eStop + (searchExt->MarginStop * 60);
- int Flags = Timer->Flags();
- if (searchExt->useVPS && pEvent->Vps() && Setup.UseVps)
- {
- start = pEvent->Vps();
- stop = start + pEvent->Duration();
- }
- else
- Flags = 1; // don't use VPS, if not set in this search
-
- if (searchExt->action == searchTimerActionInactiveRecord)
- Flags &= ~tfActive;
-
- // already done the same timer?
- if (!EPGSearchConfig.TimerProgRepeat && index == 0 && TimersDone.InList(start, stop, pEvent, -1))
- {
- LogFile.Log(2,"skip timer for '%s~%s' (%s - %s); search timer: '%s' - already done", pEvent->Title(), pEvent->ShortText()?pEvent->ShortText():"", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), searchExt->search);
- return false;
- }
-
- strftime(bufStart, sizeof(bufStart), "%H%M", localtime_r(&start, &tm_r));
- strftime(bufEnd, sizeof(bufEnd), "%H%M", localtime_r(&stop, &tm_r));
-
- // add additional info
- char* tmpSummary = NULL;
- if (Summary)
- {
- tmpSummary = strdup(Summary);
- strreplace(tmpSummary, '\n', '|');
- }
- else
- tmpSummary = SummaryExtended(searchExt, Timer, pEvent);
- if (index==0)
- msprintf(&cmdbuf, "NEWT %d:%d:%s:%s:%s:%d:%d:%s:%s",
- Flags,
- Timer->Channel()->Number(),
- *Timer->PrintDay(start, Timer->WeekDays(), true),
- bufStart,
- bufEnd,
- Prio,
- Lifetime,
- Timer->File(),
- tmpSummary?tmpSummary:"");
- else
- msprintf(&cmdbuf, "MODT %d %d:%d:%s:%s:%s:%d:%d:%s:%s",
- index,
- Flags,
- Timer->Channel()->Number(),
- *Timer->PrintDay(start, Timer->WeekDays(), true),
- bufStart,
- bufEnd,
- Prio,
- Lifetime,
- Timer->File(),
- tmpSummary?tmpSummary:"");
-
- if (!SendViaSVDRP(cmdbuf))
- return false;
-
- if (gl_timerStatusMonitor) gl_timerStatusMonitor->SetConflictCheckAdvised();
-
- cTimerDone* timerdone = new cTimerDone(start, stop, pEvent, searchExt->ID);
- if (index==0)
- TimersDone.Add(timerdone);
- else
- TimersDone.Update(start, stop, pEvent, searchExt->ID, timerdone);
-
- if (EPGSearchConfig.sendMailOnSearchtimers)
- {
- if (index==0) // new
- mailNotifier.AddNewTimerNotification(pEvent->EventID(), pEvent->ChannelID());
- else
- mailNotifier.AddModTimerNotification(pEvent->EventID(), pEvent->ChannelID(), timerMod);
- }
- free(cmdbuf);
- if (tmpSummary) free(tmpSummary);
-
- return true;
+ char *cmdbuf = NULL;
+
+ static char bufStart[25];
+ static char bufEnd[25];
+
+ struct tm tm_r;
+ time_t eStart = pEvent->StartTime();
+ time_t eStop = pEvent->EndTime();
+ time_t start = eStart - (searchExt->MarginStart * 60);
+ time_t stop = eStop + (searchExt->MarginStop * 60);
+ int Flags = Timer->Flags();
+ if (searchExt->useVPS && pEvent->Vps() && Setup.UseVps) {
+ start = pEvent->Vps();
+ stop = start + pEvent->Duration();
+ } else
+ Flags = 1; // don't use VPS, if not set in this search
+
+ if (searchExt->action == searchTimerActionInactiveRecord)
+ Flags &= ~tfActive;
+
+ // already done the same timer?
+ if (!EPGSearchConfig.TimerProgRepeat && index == 0 && TimersDone.InList(start, stop, pEvent, -1)) {
+ LogFile.Log(2, "skip timer for '%s~%s' (%s - %s); search timer: '%s' - already done", pEvent->Title(), pEvent->ShortText() ? pEvent->ShortText() : "", GETDATESTRING(pEvent), GETTIMESTRING(pEvent), searchExt->search);
+ return false;
+ }
+
+ strftime(bufStart, sizeof(bufStart), "%H%M", localtime_r(&start, &tm_r));
+ strftime(bufEnd, sizeof(bufEnd), "%H%M", localtime_r(&stop, &tm_r));
+
+ // add additional info
+ char* tmpSummary = NULL;
+ if (Summary) {
+ tmpSummary = strdup(Summary);
+ strreplace(tmpSummary, '\n', '|');
+ } else
+ tmpSummary = SummaryExtended(searchExt, Timer, pEvent);
+ if (index == 0)
+ msprintf(&cmdbuf, "NEWT %d:%d:%s:%s:%s:%d:%d:%s:%s",
+ Flags,
+ Timer->Channel()->Number(),
+ *Timer->PrintDay(start, Timer->WeekDays(), true),
+ bufStart,
+ bufEnd,
+ Prio,
+ Lifetime,
+ Timer->File(),
+ tmpSummary ? tmpSummary : "");
+ else
+ msprintf(&cmdbuf, "MODT %d %d:%d:%s:%s:%s:%d:%d:%s:%s",
+ index,
+ Flags,
+ Timer->Channel()->Number(),
+ *Timer->PrintDay(start, Timer->WeekDays(), true),
+ bufStart,
+ bufEnd,
+ Prio,
+ Lifetime,
+ Timer->File(),
+ tmpSummary ? tmpSummary : "");
+
+ if (!SendViaSVDRP(cmdbuf))
+ return false;
+
+ if (gl_timerStatusMonitor) gl_timerStatusMonitor->SetConflictCheckAdvised();
+
+ cTimerDone* timerdone = new cTimerDone(start, stop, pEvent, searchExt->ID);
+ if (index == 0)
+ TimersDone.Add(timerdone);
+ else
+ TimersDone.Update(start, stop, pEvent, searchExt->ID, timerdone);
+
+ if (EPGSearchConfig.sendMailOnSearchtimers) {
+ if (index == 0) // new
+ mailNotifier.AddNewTimerNotification(pEvent->EventID(), pEvent->ChannelID());
+ else
+ mailNotifier.AddModTimerNotification(pEvent->EventID(), pEvent->ChannelID(), timerMod);
+ }
+ free(cmdbuf);
+ if (tmpSummary) free(tmpSummary);
+
+ return true;
}
void cSearchTimerThread::RemoveTimer(const cTimer* t, const cEvent* e)
{
- if (!t) return;
- if (EPGSearchConfig.sendMailOnSearchtimers)
- mailNotifier.AddRemoveTimerNotification(t,e);
- if (!EPGSearchConfig.TimerProgRepeat)
- {
- cTimerDone * TimerDone = TimersDone.InList(t->StartTime(), t->StopTime(), e, -1);
- if (TimerDone)
- {
- cMutexLock TimersDoneLock(&TimersDone);
- TimersDone.Del(TimerDone);
- TimersDone.Save();
- }
- }
- DelTimer(t->Id());
+ if (!t) return;
+ if (EPGSearchConfig.sendMailOnSearchtimers)
+ mailNotifier.AddRemoveTimerNotification(t, e);
+ if (!EPGSearchConfig.TimerProgRepeat) {
+ cTimerDone * TimerDone = TimersDone.InList(t->StartTime(), t->StopTime(), e, -1);
+ if (TimerDone) {
+ cMutexLock TimersDoneLock(&TimersDone);
+ TimersDone.Del(TimerDone);
+ TimersDone.Save();
+ }
+ }
+ DelTimer(t->Id());
}
void cSearchTimerThread::DelRecording(int index)
{
- cString cmdbuf = cString::sprintf("DELR %d", index);
- LogFile.Log(2, "delete recording %d", index);
- SendViaSVDRP(cmdbuf);
+ cString cmdbuf = cString::sprintf("DELR %d", index);
+ LogFile.Log(2, "delete recording %d", index);
+ SendViaSVDRP(cmdbuf);
}
void cSearchTimerThread::CheckExpiredRecs()
{
- LogFile.Log(1, "check for expired recordings started");
- LOCK_RECORDINGS_WRITE;
- Recordings->SetExplicitModify();
- cList<cRecordingObj> DelRecordings;
- for (cRecording *recording = Recordings->First(); recording && m_Active; recording = Recordings->Next(recording))
- {
- LogFile.Log(3, "check recording %s from %s for expiration", recording->Name(), DAYDATETIME(recording->Start()));
- if (recording->Start() == 0)
- {
- LogFile.Log(2, "oops, recording %s has no start time, skipped", recording->Name());
- continue;
- }
- if (recording->IsEdited()) continue;
-
- if (!recording->Info()) continue;
- char* searchID = GetAuxValue(recording, "s-id");
- char* searchName = GetAuxValue(recording, "searchtimer");
- if (!searchName)
- searchName = GetAuxValue(recording, "search timer");
-
- if (!searchID || !searchName)
- {
- if (searchID) free(searchID);
- if (searchName) free(searchName);
- continue;
- }
- cSearchExt* search = SearchExts.GetSearchFromID(atoi(searchID));
- if (!search || strcmp(search->search, searchName) != 0)
- {
- if (searchID) free(searchID);
- if (searchName) free(searchName);
- continue;
- }
- free(searchID);
- free(searchName);
- LogFile.Log(3, "recording triggered from search timer %s", search->search);
- if (search->delAfterDays == 0) continue;
- time_t now = time(NULL);
-
- int daysBetween = int(double((now - recording->Start())) / (60*60*24));
- if (daysBetween >= search->delAfterDays)
- DelRecordings.Add(new cRecordingObj(recording, search));
- else
- LogFile.Log(3, "recording will expire in %d days, search timer %s", search->delAfterDays - daysBetween, search->search);
- }
- for (cRecordingObj *recordingObj = DelRecordings.First(); recordingObj && m_Active; recordingObj = DelRecordings.Next(recordingObj))
- {
- cRecording* recording = recordingObj->recording;
- cSearchExt* search = recordingObj->search;
- if (search->recordingsKeep > 0 && search->recordingsKeep >= search->GetCountRecordings())
- {
- LogFile.Log(1, "recording '%s' from %s expired, but will be kept, search timer %s", recording->Name(), DAYDATETIME(recording->Start()), recordingObj->search->search);
- continue;
- }
- LogFile.Log(1, "delete expired recording '%s' from %s, search timer %s", recording->Name(), DAYDATETIME(recording->Start()), recordingObj->search->search);
- cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
- if (!rc)
- {
- if (!recording->Delete())
- LogFile.Log(1, "error deleting recording!");
- else
- {
- Recordings->DelByName(recording->FileName());
- Recordings->SetModified();
- }
- }
- else
- LogFile.Log(1, "recording already in use by a timer!");
- }
- LogFile.Log(1, "check for expired recordings finished");
+ LogFile.Log(1, "check for expired recordings started");
+ LOCK_RECORDINGS_WRITE;
+ Recordings->SetExplicitModify();
+ cList<cRecordingObj> DelRecordings;
+ for (cRecording *recording = Recordings->First(); recording && m_Active; recording = Recordings->Next(recording)) {
+ LogFile.Log(3, "check recording %s from %s for expiration", recording->Name(), DAYDATETIME(recording->Start()));
+ if (recording->Start() == 0) {
+ LogFile.Log(2, "oops, recording %s has no start time, skipped", recording->Name());
+ continue;
+ }
+ if (recording->IsEdited()) continue;
+
+ if (!recording->Info()) continue;
+ char* searchID = GetAuxValue(recording, "s-id");
+ char* searchName = GetAuxValue(recording, "searchtimer");
+ if (!searchName)
+ searchName = GetAuxValue(recording, "search timer");
+
+ if (!searchID || !searchName) {
+ if (searchID) free(searchID);
+ if (searchName) free(searchName);
+ continue;
+ }
+ cSearchExt* search = SearchExts.GetSearchFromID(atoi(searchID));
+ if (!search || strcmp(search->search, searchName) != 0) {
+ if (searchID) free(searchID);
+ if (searchName) free(searchName);
+ continue;
+ }
+ free(searchID);
+ free(searchName);
+ LogFile.Log(3, "recording triggered from search timer %s", search->search);
+ if (search->delAfterDays == 0) continue;
+ time_t now = time(NULL);
+
+ int daysBetween = int(double((now - recording->Start())) / (60 * 60 * 24));
+ if (daysBetween >= search->delAfterDays)
+ DelRecordings.Add(new cRecordingObj(recording, search));
+ else
+ LogFile.Log(3, "recording will expire in %d days, search timer %s", search->delAfterDays - daysBetween, search->search);
+ }
+ for (cRecordingObj *recordingObj = DelRecordings.First(); recordingObj && m_Active; recordingObj = DelRecordings.Next(recordingObj)) {
+ cRecording* recording = recordingObj->recording;
+ cSearchExt* search = recordingObj->search;
+ if (search->recordingsKeep > 0 && search->recordingsKeep >= search->GetCountRecordings()) {
+ LogFile.Log(1, "recording '%s' from %s expired, but will be kept, search timer %s", recording->Name(), DAYDATETIME(recording->Start()), recordingObj->search->search);
+ continue;
+ }
+ LogFile.Log(1, "delete expired recording '%s' from %s, search timer %s", recording->Name(), DAYDATETIME(recording->Start()), recordingObj->search->search);
+ cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
+ if (!rc) {
+ if (!recording->Delete())
+ LogFile.Log(1, "error deleting recording!");
+ else {
+ Recordings->DelByName(recording->FileName());
+ Recordings->SetModified();
+ }
+ } else
+ LogFile.Log(1, "recording already in use by a timer!");
+ }
+ LogFile.Log(1, "check for expired recordings finished");
}
void cSearchTimerThread::ModifyManualTimer(const cEvent* event, const cTimer* timer, int bstart, int bstop)
{
- LogFile.Log(1,"modified manual timer %d for '%s~%s' (%s - %s)", timer->Id(), event->Title(), event->ShortText()?event->ShortText():"", GETDATESTRING(event), GETTIMESTRING(event));
-
- time_t start = event->StartTime() - bstart;
- time_t stop = event->EndTime() + bstop;
- struct tm tm_r_start;
- struct tm tm_r_stop;
- localtime_r(&start, &tm_r_start);
- localtime_r(&stop, &tm_r_stop);
- char daybuffer[DAYBUFFERSIZE];
- char startbuffer[DAYBUFFERSIZE];
- char stopbuffer[DAYBUFFERSIZE];
- strftime(daybuffer, DAYBUFFERSIZE, "%Y-%m-%d", &tm_r_start);
- strftime(startbuffer, DAYBUFFERSIZE, "%H%M", &tm_r_start);
- strftime(stopbuffer, DAYBUFFERSIZE, "%H%M", &tm_r_stop);
-
- char* cmdbuf = NULL;
- msprintf(&cmdbuf, "MODT %d %d:%d:%s:%s:%s:%d:%d:%s:%s",
- timer->Id(),
- timer->Flags(),
- timer->Channel()->Number(),
- daybuffer,
- startbuffer,
- stopbuffer,
- timer->Priority(),
- timer->Lifetime(),
- timer->File(),
- timer->Aux());
-
- if (EPGSearchConfig.sendMailOnSearchtimers)
- mailNotifier.AddModTimerNotification(event->EventID(), event->ChannelID());
-
- cTimerThread timerThread;
- timerThread.Init(cmdbuf);
- free(cmdbuf);
+ LogFile.Log(1, "modified manual timer %d for '%s~%s' (%s - %s)", timer->Id(), event->Title(), event->ShortText() ? event->ShortText() : "", GETDATESTRING(event), GETTIMESTRING(event));
+
+ time_t start = event->StartTime() - bstart;
+ time_t stop = event->EndTime() + bstop;
+ struct tm tm_r_start;
+ struct tm tm_r_stop;
+ localtime_r(&start, &tm_r_start);
+ localtime_r(&stop, &tm_r_stop);
+ char daybuffer[DAYBUFFERSIZE];
+ char startbuffer[DAYBUFFERSIZE];
+ char stopbuffer[DAYBUFFERSIZE];
+ strftime(daybuffer, DAYBUFFERSIZE, "%Y-%m-%d", &tm_r_start);
+ strftime(startbuffer, DAYBUFFERSIZE, "%H%M", &tm_r_start);
+ strftime(stopbuffer, DAYBUFFERSIZE, "%H%M", &tm_r_stop);
+
+ char* cmdbuf = NULL;
+ msprintf(&cmdbuf, "MODT %d %d:%d:%s:%s:%s:%d:%d:%s:%s",
+ timer->Id(),
+ timer->Flags(),
+ timer->Channel()->Number(),
+ daybuffer,
+ startbuffer,
+ stopbuffer,
+ timer->Priority(),
+ timer->Lifetime(),
+ timer->File(),
+ timer->Aux());
+
+ if (EPGSearchConfig.sendMailOnSearchtimers)
+ mailNotifier.AddModTimerNotification(event->EventID(), event->ChannelID());
+
+ cTimerThread timerThread;
+ timerThread.Init(cmdbuf);
+ free(cmdbuf);
}
void cSearchTimerThread::CheckManualTimers(void)
{
- LogFile.Log(1, "manual timer check started");
+ LogFile.Log(1, "manual timer check started");
LOCK_TIMERS_READ;
LOCK_SCHEDULES_READ;
- for (const cTimer *ti = Timers->First(); ti && m_Active; ti = Timers->Next(ti))
- {
- if (TriggeredFromSearchTimerID(ti) != -1) continue; // manual timer?
-
- if (TimerWasModified(ti))
- {
- LogFile.Log(2,"timer for '%s' (%s, channel %s) modified by user - won't be touched", ti->File(), DAYDATETIME(ti->StartTime()), CHANNELNAME(ti->Channel()));
- continue; // don't update timers modified by user
- }
-
- char* szbstart = GetAuxValue(ti, "bstart");
- int bstart = szbstart? atoi(szbstart) : 0;
- free(szbstart);
- char* szbstop = GetAuxValue(ti, "bstop");
- int bstop = szbstop? atoi(szbstop) : 0;
- free(szbstop);
-
- // how to check?
- char* updateMethod = GetAuxValue(ti, "update");
- if (updateMethod && atoi(updateMethod) == UPD_EVENTID) // by event ID?
- {
- // get the channels schedule
- const cSchedule* schedule = Schedules->GetSchedule(ti->Channel());
- if (schedule)
- {
- tEventID eventID = 0;
- char* szEventID = GetAuxValue(ti, "eventid");
- if (szEventID)
- eventID = atol(szEventID);
- LogFile.Log(3,"checking manual timer %d by event ID %u", ti->Id(), eventID);
- const cEvent* event = schedule->GetEvent(eventID);
- if (event)
- {
- if (event->StartTime() - bstart != ti->StartTime() || event->EndTime() + bstop != ti->StopTime())
- ModifyManualTimer(event, ti, bstart, bstop);
+ for (const cTimer *ti = Timers->First(); ti && m_Active; ti = Timers->Next(ti)) {
+ if (TriggeredFromSearchTimerID(ti) != -1) continue; // manual timer?
+
+ if (TimerWasModified(ti)) {
+ LogFile.Log(2, "timer for '%s' (%s, channel %s) modified by user - won't be touched", ti->File(), DAYDATETIME(ti->StartTime()), CHANNELNAME(ti->Channel()));
+ continue; // don't update timers modified by user
+ }
+
+ char* szbstart = GetAuxValue(ti, "bstart");
+ int bstart = szbstart ? atoi(szbstart) : 0;
+ free(szbstart);
+ char* szbstop = GetAuxValue(ti, "bstop");
+ int bstop = szbstop ? atoi(szbstop) : 0;
+ free(szbstop);
+
+ // how to check?
+ char* updateMethod = GetAuxValue(ti, "update");
+ if (updateMethod && atoi(updateMethod) == UPD_EVENTID) { // by event ID?
+ // get the channels schedule
+ const cSchedule* schedule = Schedules->GetSchedule(ti->Channel());
+ if (schedule) {
+ tEventID eventID = 0;
+ char* szEventID = GetAuxValue(ti, "eventid");
+ if (szEventID)
+ eventID = atol(szEventID);
+ LogFile.Log(3, "checking manual timer %d by event ID %u", ti->Id(), eventID);
+ const cEvent* event = schedule->GetEvent(eventID);
+ if (event) {
+ if (event->StartTime() - bstart != ti->StartTime() || event->EndTime() + bstop != ti->StopTime())
+ ModifyManualTimer(event, ti, bstart, bstop);
+ } else
+ LogFile.Log(1, "ooops - no event found with id %u for manual timer %d", eventID, ti->Id());
+
+ if (szEventID) free(szEventID);
}
- else
- LogFile.Log(1,"ooops - no event found with id %u for manual timer %d", eventID, ti->Id());
-
- if (szEventID) free(szEventID);
- }
- }
- if (updateMethod && atoi(updateMethod) == UPD_CHDUR) // by channel and time?
- {
- // get the channels schedule
- const cSchedule* schedule = Schedules->GetSchedule(ti->Channel());
- if (schedule)
- {
- // collect all events touching the old timer margins
- cSearchResults eventlist;
- for (const cEvent *testevent = schedule->Events()->First(); testevent; testevent = schedule->Events()->Next(testevent))
- {
- if (testevent->StartTime() < ti->StopTime() && testevent->EndTime() > ti->StartTime())
- eventlist.Add(new cSearchResult(testevent, (const cSearchExt*)NULL));
+ }
+ if (updateMethod && atoi(updateMethod) == UPD_CHDUR) { // by channel and time?
+ // get the channels schedule
+ const cSchedule* schedule = Schedules->GetSchedule(ti->Channel());
+ if (schedule) {
+ // collect all events touching the old timer margins
+ cSearchResults eventlist;
+ for (const cEvent *testevent = schedule->Events()->First(); testevent; testevent = schedule->Events()->Next(testevent)) {
+ if (testevent->StartTime() < ti->StopTime() && testevent->EndTime() > ti->StartTime())
+ eventlist.Add(new cSearchResult(testevent, (const cSearchExt*)NULL));
+ }
+ LogFile.Log(3, "checking manual timer %d by channel and time, found %d candidates", ti->Id(), eventlist.Count());
+ if (eventlist.Count() > 0) {
+ // choose the event with the best match by duration
+ long origlen = (ti->StopTime() - bstop) - (ti->StartTime() + bstart);
+ double maxweight = 0;
+ const cEvent* event = eventlist.First()->event;
+ for (cSearchResult* pResultObj = eventlist.First(); pResultObj; pResultObj = eventlist.Next(pResultObj)) {
+ const cEvent* testevent = pResultObj->event;
+ time_t start = (testevent->StartTime() < ti->StartTime()) ? ti->StartTime() : testevent->StartTime();
+ time_t stop = (testevent->EndTime() > ti->StopTime()) ? ti->StopTime() : testevent->EndTime();
+ double weight = double(stop - start) / double(testevent->EndTime() - testevent->StartTime());
+ LogFile.Log(3, "candidate '%s~%s' (%s - %s) timer match: %f, duration match: %f", testevent->Title(), testevent->ShortText() ? testevent->ShortText() : "", GETDATESTRING(testevent), GETTIMESTRING(testevent), weight, (double(testevent->EndTime() - testevent->StartTime()) / origlen));
+ if (weight > maxweight && (double(testevent->EndTime() - testevent->StartTime()) / origlen) >= 0.9) {
+ maxweight = weight;
+ event = testevent;
+ }
+ }
+ LogFile.Log(3, "selected candidate is '%s~%s' (%s - %s)", event->Title(), event->ShortText() ? event->ShortText() : "", GETDATESTRING(event), GETTIMESTRING(event));
+ if ((maxweight > 0 && event->StartTime() - bstart != ti->StartTime()) || (event->EndTime() + bstop != ti->StopTime()))
+ ModifyManualTimer(event, ti, bstart, bstop);
+ else if (maxweight <= 0)
+ LogFile.Log(3, "selected candidate is too bad");
+ } else
+ LogFile.Log(1, "ooops - no events found touching manual timer %d", ti->Id());
}
- LogFile.Log(3,"checking manual timer %d by channel and time, found %d candidates", ti->Id(), eventlist.Count());
- if (eventlist.Count() > 0)
- {
- // choose the event with the best match by duration
- long origlen = (ti->StopTime() - bstop) - (ti->StartTime() + bstart);
- double maxweight = 0;
- const cEvent* event = eventlist.First()->event;
- for (cSearchResult* pResultObj = eventlist.First(); pResultObj; pResultObj = eventlist.Next(pResultObj))
- {
- const cEvent* testevent = pResultObj->event;
- time_t start = (testevent->StartTime() < ti->StartTime()) ? ti->StartTime() : testevent->StartTime();
- time_t stop = (testevent->EndTime() > ti->StopTime()) ? ti->StopTime() : testevent->EndTime();
- double weight = double(stop - start) / double(testevent->EndTime() - testevent->StartTime());
- LogFile.Log(3,"candidate '%s~%s' (%s - %s) timer match: %f, duration match: %f", testevent->Title(), testevent->ShortText()?testevent->ShortText():"", GETDATESTRING(testevent), GETTIMESTRING(testevent), weight, (double(testevent->EndTime() - testevent->StartTime()) / origlen));
- if (weight > maxweight && (double(testevent->EndTime() - testevent->StartTime()) / origlen) >= 0.9)
- {
- maxweight = weight;
- event = testevent;
- }
- }
- LogFile.Log(3,"selected candidate is '%s~%s' (%s - %s)", event->Title(), event->ShortText()?event->ShortText():"", GETDATESTRING(event), GETTIMESTRING(event));
- if ((maxweight > 0 && event->StartTime() - bstart != ti->StartTime()) || (event->EndTime() + bstop != ti->StopTime()))
- ModifyManualTimer(event, ti, bstart, bstop);
- else if (maxweight <= 0)
- LogFile.Log(3,"selected candidate is too bad");
- }
- else
- LogFile.Log(1,"ooops - no events found touching manual timer %d", ti->Id());
- }
- if (updateMethod) free(updateMethod);
- }
- }
- LogFile.Log(1, "manual timer check finished");
+ if (updateMethod) free(updateMethod);
+ }
+ }
+ LogFile.Log(1, "manual timer check finished");
}
// check if EPG is present for the configured hours
void cSearchTimerThread::CheckEPGHours()
{
- if (EPGSearchConfig.checkEPGHours <= 0 ||
- (EPGSearchConfig.checkEPGWarnByOSD == 0 && EPGSearchConfig.checkEPGWarnByMail == 0) ||
- EPGSearchConfig.checkEPGchannelGroupNr <= 0)
- return;
-
- LogFile.Log(2,"check if relevant EPG exists for the next %d hours", EPGSearchConfig.checkEPGHours);
- cChannelGroup* channelGroup = ChannelGroups.Get(EPGSearchConfig.checkEPGchannelGroupNr-1); // not zero-based!
- if (!channelGroup)
- {
- LogFile.Log(1,"channel group with index %d does not exist!", EPGSearchConfig.checkEPGchannelGroupNr);
- return;
+ if (EPGSearchConfig.checkEPGHours <= 0 ||
+ (EPGSearchConfig.checkEPGWarnByOSD == 0 && EPGSearchConfig.checkEPGWarnByMail == 0) ||
+ EPGSearchConfig.checkEPGchannelGroupNr <= 0)
+ return;
+
+ LogFile.Log(2, "check if relevant EPG exists for the next %d hours", EPGSearchConfig.checkEPGHours);
+ cChannelGroup* channelGroup = ChannelGroups.Get(EPGSearchConfig.checkEPGchannelGroupNr - 1); // not zero-based!
+ if (!channelGroup) {
+ LogFile.Log(1, "channel group with index %d does not exist!", EPGSearchConfig.checkEPGchannelGroupNr);
+ return;
}
- LogFile.Log(2,"checking channel group '%s'", channelGroup->name);
+ LogFile.Log(2, "checking channel group '%s'", channelGroup->name);
- time_t checkTime = time(NULL) + EPGSearchConfig.checkEPGHours * 60 * 60;
+ time_t checkTime = time(NULL) + EPGSearchConfig.checkEPGHours * 60 * 60;
LOCK_SCHEDULES_READ;
- cChannelGroup channelsWithSmallEPG;
- cChannelGroupItem* channelInGroup = channelGroup->channels.First();
- while (channelInGroup)
- {
- const cChannel* channel = channelInGroup->channel;
- // get the channels schedule
- const cSchedule* schedule = Schedules->GetSchedule(channel);
- if (!schedule || !schedule->GetEventAround(checkTime))
- {
- LogFile.Log(3,"less than %d hours of EPG for channel %s!", EPGSearchConfig.checkEPGHours, channel->Name());
- cChannelGroupItem* channelitem = new cChannelGroupItem(channel);
- channelsWithSmallEPG.channels.Add(channelitem);
- }
- channelInGroup = channelGroup->channels.Next(channelInGroup);
+ cChannelGroup channelsWithSmallEPG;
+ cChannelGroupItem* channelInGroup = channelGroup->channels.First();
+ while (channelInGroup) {
+ const cChannel* channel = channelInGroup->channel;
+ // get the channels schedule
+ const cSchedule* schedule = Schedules->GetSchedule(channel);
+ if (!schedule || !schedule->GetEventAround(checkTime)) {
+ LogFile.Log(3, "less than %d hours of EPG for channel %s!", EPGSearchConfig.checkEPGHours, channel->Name());
+ cChannelGroupItem* channelitem = new cChannelGroupItem(channel);
+ channelsWithSmallEPG.channels.Add(channelitem);
+ }
+ channelInGroup = channelGroup->channels.Next(channelInGroup);
}
- // create a string list of the channels found
- if (channelsWithSmallEPG.channels.Count() > 0)
- {
- string sBuffer;
- channelInGroup = channelsWithSmallEPG.channels.First();
- while (channelInGroup)
- {
- const cChannel* channel = channelInGroup->channel;
- if (channel)
- sBuffer += " " + string(channel->ShortName(true));
- channelInGroup = channelsWithSmallEPG.channels.Next(channelInGroup);
- }
-
-
- if (EPGSearchConfig.checkEPGWarnByOSD)
- {
- cString msgfmt = cString::sprintf(tr("small EPG content on:%s"), sBuffer.c_str());
- SendMsg(msgfmt, false, 0, mtWarning);
- }
- if (EPGSearchConfig.checkEPGWarnByMail)
- {
- cString msgfmt = cString::sprintf(tr("small EPG content on:%s"), sBuffer.c_str());
- cMailNotifier M(string(tr("VDR EPG check warning")), string(msgfmt));
- }
+ // create a string list of the channels found
+ if (channelsWithSmallEPG.channels.Count() > 0) {
+ string sBuffer;
+ channelInGroup = channelsWithSmallEPG.channels.First();
+ while (channelInGroup) {
+ const cChannel* channel = channelInGroup->channel;
+ if (channel)
+ sBuffer += " " + string(channel->ShortName(true));
+ channelInGroup = channelsWithSmallEPG.channels.Next(channelInGroup);
+ }
+
+
+ if (EPGSearchConfig.checkEPGWarnByOSD) {
+ cString msgfmt = cString::sprintf(tr("small EPG content on:%s"), sBuffer.c_str());
+ SendMsg(msgfmt, false, 0, mtWarning);
+ }
+ if (EPGSearchConfig.checkEPGWarnByMail) {
+ cString msgfmt = cString::sprintf(tr("small EPG content on:%s"), sBuffer.c_str());
+ cMailNotifier M(string(tr("VDR EPG check warning")), string(msgfmt));
+ }
}
- LogFile.Log(2,"check for relevant EPG finished - %d channels with small EPG content", channelsWithSmallEPG.channels.Count());
+ LogFile.Log(2, "check for relevant EPG finished - %d channels with small EPG content", channelsWithSmallEPG.channels.Count());
}