/* -*- c++ -*- Copyright (C) 2004-2013 Christian Wieninger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch */ #include #include #include #include #include "epgsearchservices.h" #include "epgsearchext.h" #include "epgsearchcfg.h" #include "searchtimer_thread.h" #include "epgsearchcats.h" #include "changrp.h" #include "blacklist.h" #include "menu_dirselect.h" #include "epgsearchtools.h" #include "conflictcheck.h" #include "timerstatus.h" #include "uservars.h" std::list cEpgsearchServiceHandler::SearchTimerList() { std::list list; cMutexLock SearchExtsLock(&SearchExts); for (int i = 0; i < SearchExts.Count(); i++) { cSearchExt* search = SearchExts.Get(i); if (search) list.push_back(search->ToText()); } return list; } int cEpgsearchServiceHandler::AddSearchTimer(const std::string& settings) { cSearchExt* search = new cSearchExt; if (search->Parse(settings.c_str())) { search->ID = SearchExts.GetNewID(); LogFile.Log(1,"added search '%s' (%d) via service interface", search->search, search->ID); cMutexLock SearchExtsLock(&SearchExts); SearchExts.Add(search); SearchExts.Save(); if (search->useAsSearchTimer && !EPGSearchConfig.useSearchTimers) // enable search timer thread if necessary cSearchTimerThread::Init((cPluginEpgsearch*) cPluginManager::GetPlugin("epgsearch"), true); return search->ID; } else { LogFile.Log(1,"error adding '%s' via service interface", search->search); delete search; return -1; } } bool cEpgsearchServiceHandler::ModSearchTimer(const std::string& settings) { cSearchExt Search; if (Search.Parse(settings.c_str())) { cSearchExt *searchTemp = SearchExts.GetSearchFromID(Search.ID); if (searchTemp) { searchTemp->Parse(settings.c_str()); LogFile.Log(1,"modified search '%s' (%d) via service interface", searchTemp->search, searchTemp->ID); SearchExts.Save(); if (searchTemp->useAsSearchTimer && !EPGSearchConfig.useSearchTimers) // enable search timer thread if necessary cSearchTimerThread::Init((cPluginEpgsearch*) cPluginManager::GetPlugin("epgsearch"), true); return true; } } else { LogFile.Log(1,"error modifying '%s' via service interface", settings.c_str()); } return false; } bool cEpgsearchServiceHandler::DelSearchTimer(int ID) { cSearchExt *search = SearchExts.GetSearchFromID(ID); if (search) { LogFile.Log(1,"search '%s' deleted via service interface", search->search); cMutexLock SearchExtsLock(&SearchExts); SearchExts.Del(search); SearchExts.Save(); RecsDone.RemoveSearchID(ID); return true; } else LogFile.Log(1,"error deleting search with id '%d' via service interface", ID); return false; } std::list cEpgsearchServiceHandler::TranslateResults(cSearchResults* pCompleteSearchResults) { std::list list; if (pCompleteSearchResults) { // transfer to result list pCompleteSearchResults->SortBy(CompareEventTime); cSearchResult *result = pCompleteSearchResults->First(); while (result && result->search) { const cEvent* pEvent = result->event; cTimer* Timer = new cTimer(pEvent); 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 - (result->search->MarginStart * 60); time_t stop = eStop + (result->search->MarginStop * 60); if (result->search->useVPS && pEvent->Vps() && Setup.UseVps) { start = pEvent->Vps(); stop = start + pEvent->Duration(); } strftime(bufStart, sizeof(bufStart), "%H%M", localtime_r(&start, &tm_r)); strftime(bufEnd, sizeof(bufEnd), "%H%M", localtime_r(&stop, &tm_r)); eTimerMatch timerMatch; bool hasTimer = false; LOCK_TIMERS_READ; if (Timers->GetMatch(pEvent, &timerMatch)) hasTimer = (timerMatch == tmFull); if (!result->search->useAsSearchTimer) result->needsTimer = false; LOCK_CHANNELS_READ; const cChannel *channel = Channels->GetByChannelID(pEvent->ChannelID(), true, true); int timerMode = hasTimer?1:(result->needsTimer?2:0); std::string title = pEvent->Title()?ReplaceAll(pEvent->Title(), "|", "!^pipe!^"):""; title = ReplaceAll(title, ":", "|"); std::string shorttext = pEvent->ShortText()?ReplaceAll(pEvent->ShortText(), "|", "!^pipe!^"):""; shorttext = ReplaceAll(shorttext, ":", "|"); std::string description = pEvent->Description()?ReplaceAll(pEvent->Description(), "|", "!^pipe!^"):""; description = ReplaceAll(description, ":", "|"); cString cmdbuf = cString::sprintf("%d:%u:%s:%s:%s:%ld:%ld:%s:%ld:%ld:%s:%d", result->search->ID, pEvent->EventID(), title.c_str(), shorttext.c_str(), description.c_str(), pEvent->StartTime(), pEvent->EndTime(), CHANNELSTRING(channel), timerMode>0?start:-1, timerMode>0?stop:-1, timerMode>0?result->search->BuildFile(pEvent):"", timerMode); list.push_back(*cmdbuf); delete(Timer); result = pCompleteSearchResults->Next(result); } } return list; } std::list cEpgsearchServiceHandler::QuerySearchTimer(int ID) { std::list list; cSearchResults* pCompleteSearchResults = NULL; cSearchExt* search = SearchExts.GetSearchFromID(ID); if (!search) return list; pCompleteSearchResults = search->Run(); list = TranslateResults(pCompleteSearchResults); if (pCompleteSearchResults) delete pCompleteSearchResults; return list; } std::list cEpgsearchServiceHandler::QuerySearch(std::string query) { std::list list; cSearchExt* temp_SearchExt = new cSearchExt; if (temp_SearchExt->Parse(query.c_str())) { cSearchResults* pCompleteSearchResults = temp_SearchExt->Run(); list = TranslateResults(pCompleteSearchResults); if (pCompleteSearchResults) delete pCompleteSearchResults; } delete temp_SearchExt; return list; } std::list cEpgsearchServiceHandler::ExtEPGInfoList() { std::list list; for (int i = 0; i < SearchExtCats.Count(); i++) { cSearchExtCat *SearchExtCat = SearchExtCats.Get(i); if (SearchExtCat) list.push_back(SearchExtCat->ToText()); } return list; } std::list cEpgsearchServiceHandler::ChanGrpList() { std::list list; for (int i = 0; i < ChannelGroups.Count(); i++) { cChannelGroup *changrp = ChannelGroups.Get(i); if (changrp) list.push_back(changrp->ToText()); } return list; } std::list cEpgsearchServiceHandler::BlackList() { std::list list; cMutexLock BlacklistLock(&Blacklists); for (int i = 0; i < Blacklists.Count(); i++) { cBlacklist* blacklist = Blacklists.Get(i); if (blacklist) list.push_back(blacklist->ToText()); } return list; } std::set cEpgsearchServiceHandler::DirectoryList() { cMenuDirSelect::CreateDirSet(); return cMenuDirSelect::directorySet; } std::string cEpgsearchServiceHandler::ReadSetupValue(const std::string& entry) { if (entry == "DefPriority") return NumToString(EPGSearchConfig.DefPriority); if (entry == "DefLifetime") return NumToString(EPGSearchConfig.DefLifetime); if (entry == "DefMarginStart") return NumToString(EPGSearchConfig.DefMarginStart); if (entry == "DefMarginStop") return NumToString(EPGSearchConfig.DefMarginStop); return ""; } bool cEpgsearchServiceHandler::WriteSetupValue(const std::string& entry, const std::string& value) { return true; } std::list cEpgsearchServiceHandler::TimerConflictList(bool relOnly) { std::list list; cConflictCheck conflictCheck; conflictCheck.Check(); if ((relOnly && conflictCheck.numConflicts > 0) || conflictCheck.relevantConflicts > 0) { string sBuffer; cList* failedList = conflictCheck.GetFailed(); for(cConflictCheckTime* ct = failedList->First(); ct; ct = failedList->Next(ct)) { if (relOnly && ct->ignore) continue; std::ostringstream conflline; conflline << ct->evaltime << ":"; std::set::iterator it; std::ostringstream timerparts; for (it = ct->failedTimers.begin(); it != ct->failedTimers.end(); ++it) { if (relOnly && (*it)->ignore) continue; std::ostringstream timerpart; int recPart = (*it)->recDuration * 100 / ((*it)->stop - (*it)->start); timerpart << (*it)->timer->Id() << "|" << recPart << "|"; std::set::iterator itcc; if ((*it)->concurrentTimers) { std::ostringstream cctimers; for (itcc = (*it)->concurrentTimers->begin(); itcc != (*it)->concurrentTimers->end(); ++itcc) cctimers << (cctimers.str().empty()?"":"#") << (*itcc)->timer->Id(); timerpart << cctimers.str(); } timerparts << (timerparts.str().empty()?"":":") << timerpart.str(); } conflline << timerparts.str(); list.push_back(conflline.str()); } } // set advised to false after an external conflict check if (gl_timerStatusMonitor) gl_timerStatusMonitor->SetConflictCheckAdvised(false); return list; } bool cEpgsearchServiceHandler::IsConflictCheckAdvised() { return gl_timerStatusMonitor?gl_timerStatusMonitor->ConflictCheckAdvised():false; } std::set cEpgsearchServiceHandler::ShortDirectoryList() { cMenuDirSelect::CreateDirSet(false); return cMenuDirSelect::directorySet; } std::string cEpgsearchServiceHandler::Evaluate(const std::string& expr, const cEvent* event) { if (!event) return expr; cVarExpr varExpr(expr); return varExpr.Evaluate(event); }