void cMenuSearchMain::PrepareSchedule(cChannel *Channel) { Clear(); cString buffer = cString::sprintf("%s - %s", trVDR("Schedule"), Channel->Name()); SetTitle(buffer); cMenuTemplate* ScheduleTemplate = cTemplFile::GetTemplateByName("MenuSchedule"); eventObjects.Clear(); if (schedules) { const cSchedule *Schedule = schedules->GetSchedule(Channel); currentChannel = Channel->Number(); if (Schedule && Schedule->Events()->First()) { const cEvent *PresentEvent = Schedule->GetPresentEvent(); time_t now = time(NULL); now -= Setup.EPGLinger * 60; if (shiftTime != 0) PresentEvent = Schedule->GetEventAround(time(NULL) + shiftTime * 60); time_t lastEventDate = Schedule->Events()->First()->StartTime(); // timeb tstart; // ftime(&tstart); for (const cEvent *Event = Schedule->Events()->First(); Event; Event = Schedule->Events()->Next(Event)) { if (Event->EndTime() > now || (shiftTime==0 && Event == PresentEvent)) { if (EPGSearchConfig.showDaySeparators) { struct tm tm_rEvent; struct tm tm_rLastEvent; time_t EventDate = Event->StartTime(); struct tm *t_event = localtime_r(&EventDate, &tm_rEvent); struct tm *t_lastevent = localtime_r(&lastEventDate, &tm_rLastEvent); if (t_event->tm_mday != t_lastevent->tm_mday) { cString szSep = cString::sprintf("%s\t %s %s", MENU_SEPARATOR_ITEMS, GETDATESTRING(Event), MENU_SEPARATOR_ITEMS); cOsdItem* pSepItem = new cOsdItem(szSep); pSepItem->SetSelectable(false); Add(pSepItem); } lastEventDate = EventDate; } Add(new cMenuMyScheduleItem(Event, NULL, showNow, ScheduleTemplate), Event == PresentEvent); eventObjects.Add(Event); } } // timeb tnow; // ftime(&tnow); // isyslog("duration epgs prepsched: %d (%d)", tnow.millitm - tstart.millitm + ((tnow.millitm - tstart.millitm<0)?1000:0), Count()); } } if (shiftTime) { cString buffer = cString::sprintf("%s (%s%dh %dm)", Channel->Name(), shiftTime>0?"+":"", shiftTime/60, abs(shiftTime)%60); SetTitle(buffer); } }
void cSearchTimerThread::CheckManualTimers() { LogFile.Log(1, "manual timer check started"); cSchedulesLock schedulesLock; const cSchedules *schedules; schedules = cSchedules::Schedules(schedulesLock); for (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->Index()+1, 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->Index()+1); 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 (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->Index()+1, 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->Index()+1); } if (updateMethod) free(updateMethod); } } LogFile.Log(1, "manual timer check 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->Index()+1, 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->Index()+1, 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); }
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 // 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 additonal 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::Action(void) { if (EPGSearchConfig.useExternalSVDRP && !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"); } if (Timers.BeingEdited()) { Wait.Wait(1000); continue; } 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; 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; 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 comparision 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->Index()+1; 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); } 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)) { cTimer* t = tObj->timer; // timer could have been deleted meanwhile, so check if its still there bool found = false; for(cTimer* checkT = Timers.First(); checkT; checkT = Timers.Next(checkT)) if (checkT == t) { found = true; break; } if (!found) 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 = cString::sprintf(tr("%d timer conflict(s)! 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) == kOk) { m_plugin->showConflicts = true; cRemote::CallPlugin("epgsearch"); } } LogFile.iSysLog("check for timer conflicts - done"); } // delete expired recordings CheckExpiredRecs(); // check for updates for manual timers CheckManualTimers(); if (m_Active) mailNotifier.SendUpdateNotifications(); if ((updateForced & UPDS_WITH_OSD) && m_Active) SendMsg(tr("Search timer update done!")); // 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"); }