mirror of
https://projects.vdr-developer.org/git/vdr-plugin-tvguide.git
synced 2023-10-05 15:01:48 +02:00
890 lines
29 KiB
C
890 lines
29 KiB
C
#define __STL_CONFIG_H
|
|
|
|
#include <string>
|
|
#include <sstream>
|
|
#include <vector>
|
|
#include <algorithm>
|
|
|
|
#include <vdr/menu.h>
|
|
#include "services/remotetimers.h"
|
|
#include "tools.h"
|
|
#include "switchtimer.h"
|
|
#include "timerconflict.h"
|
|
#include <vdr/timers.h>
|
|
#include "recmanager.h"
|
|
|
|
static int CompareRecording(const void *p1, const void *p2) {
|
|
return (int)((*(cRecording **)p1)->Start() - (*(cRecording **)p2)->Start());
|
|
}
|
|
|
|
cRecManager::cRecManager(void) {
|
|
epgSearchPlugin = NULL;
|
|
epgSearchAvailable = false;
|
|
}
|
|
|
|
cRecManager::~cRecManager(void) {
|
|
}
|
|
|
|
void cRecManager::SetEPGSearchPlugin(void) {
|
|
epgSearchPlugin = cPluginManager::GetPlugin("epgsearch");
|
|
if (epgSearchPlugin) {
|
|
epgSearchAvailable = true;
|
|
}
|
|
}
|
|
|
|
bool cRecManager::RefreshRemoteTimers(void) {
|
|
cString errorMsg;
|
|
if (!pRemoteTimers->Service("RemoteTimers::RefreshTimers-v1.0", &errorMsg)) {
|
|
esyslog("tvguide: %s", *errorMsg);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool cRecManager::CheckEventForTimer(const cEvent *event) {
|
|
bool hasTimer = false;
|
|
|
|
if (config.useRemoteTimers && pRemoteTimers) {
|
|
RemoteTimers_GetMatch_v1_0 rtMatch;
|
|
rtMatch.event = event;
|
|
pRemoteTimers->Service("RemoteTimers::GetMatch-v1.0", &rtMatch);
|
|
if (rtMatch.timerMatch == tmFull)
|
|
hasTimer = true;
|
|
} else {
|
|
#if VDRVERSNUM >= 20301
|
|
eTimerMatch TimerMatch = tmNone;
|
|
LOCK_TIMERS_READ;
|
|
const cTimers *timers = Timers;
|
|
if (timers->GetMatch(event, &TimerMatch) && (TimerMatch == tmFull))
|
|
hasTimer = true;
|
|
#else
|
|
hasTimer = event->HasTimer();
|
|
#endif
|
|
}
|
|
return hasTimer;
|
|
}
|
|
|
|
const cTimer *cRecManager::GetTimerForEvent(const cEvent *event) {
|
|
const cTimer *timer = NULL;
|
|
if (config.useRemoteTimers && pRemoteTimers) {
|
|
RemoteTimers_GetMatch_v1_0 rtMatch;
|
|
rtMatch.event = event;
|
|
pRemoteTimers->Service("RemoteTimers::GetMatch-v1.0", &rtMatch);
|
|
timer = rtMatch.timer;
|
|
return timer;
|
|
}
|
|
|
|
#if VDRVERSNUM >= 20301
|
|
LOCK_TIMERS_READ;
|
|
timer = Timers->GetMatch(event);
|
|
#else
|
|
timer = Timers.GetMatch(event);
|
|
#endif
|
|
return timer;
|
|
}
|
|
|
|
cTimer *cRecManager::createTimer(const cEvent *event, std::string path) {
|
|
cTimer *timer = NULL;
|
|
if (config.useRemoteTimers && pRemoteTimers) {
|
|
timer = createRemoteTimer(event, path);
|
|
} else {
|
|
timer = createLocalTimer(event, path);
|
|
}
|
|
return timer;
|
|
}
|
|
|
|
cTimer *cRecManager::createLocalTimer(const cEvent *event, std::string path) {
|
|
cTimer *timer = new cTimer(event);
|
|
#if VDRVERSNUM >= 20301
|
|
if (Setup.SVDRPPeering && *Setup.SVDRPDefaultHost)
|
|
((cTimer*)timer)->SetRemote(Setup.SVDRPDefaultHost);
|
|
LOCK_TIMERS_WRITE;
|
|
cTimers* timers = Timers;
|
|
#else
|
|
cTimers* timers = &Timers;
|
|
#endif
|
|
cTimer *t = timers->GetTimer(timer);
|
|
if (t) {
|
|
t->OnOff();
|
|
#if VDRVERSNUM >= 20301
|
|
t->SetEvent(event);
|
|
#else
|
|
t->SetEventFromSchedule();
|
|
#endif
|
|
delete timer;
|
|
timer = t;
|
|
isyslog("timer %s reactivated", *t->ToDescr());
|
|
} else {
|
|
timers->Add(timer);
|
|
isyslog("timer %s added (active)", *timer->ToDescr());
|
|
}
|
|
SetTimerPath(timer, event, path);
|
|
timers->SetModified();
|
|
return timer;
|
|
}
|
|
|
|
cTimer *cRecManager::createRemoteTimer(const cEvent *event, std::string path) {
|
|
cTimer *t = new cTimer(event);
|
|
SetTimerPath(t, event, path);
|
|
RemoteTimers_Timer_v1_0 rt;
|
|
rt.timer = t;
|
|
pRemoteTimers->Service("RemoteTimers::GetTimer-v1.0", &rt.timer);
|
|
if (rt.timer) {
|
|
rt.timer->OnOff();
|
|
if (!pRemoteTimers->Service("RemoteTimers::ModTimer-v1.0", &rt))
|
|
rt.timer = NULL;
|
|
} else {
|
|
rt.timer = t;
|
|
if (!pRemoteTimers->Service("RemoteTimers::NewTimer-v1.0", &rt))
|
|
isyslog("%s", *rt.errorMsg);
|
|
}
|
|
RefreshRemoteTimers();
|
|
return rt.timer;
|
|
}
|
|
|
|
void cRecManager::SetTimerPath(cTimer *timer, const cEvent *event, std::string path) {
|
|
if (config.instRecFolderMode == eFolderFixed) {
|
|
Epgsearch_services_v1_2 *epgSearch = new Epgsearch_services_v1_2;
|
|
std::string recDir = config.instRecFixedFolder;
|
|
std::replace(recDir.begin(), recDir.end(), '/', '~');
|
|
if (strchr(recDir.c_str(), '%') != NULL) {
|
|
if (epgSearchPlugin->Service("Epgsearch-services-v1.1", epgSearch)) {
|
|
std::string newFileName = epgSearch->handler->Evaluate(recDir, event);
|
|
if (strchr(newFileName.c_str(), '%') == NULL) // only set directory to new value if all categories could have been replaced
|
|
timer->SetFile(newFileName.c_str());
|
|
else
|
|
esyslog("tvguide: timer path not set because replacing variable was not successfull: %s", newFileName.c_str());
|
|
}
|
|
} else {
|
|
cString newFileName;
|
|
if (recDir.size() > 0) {
|
|
newFileName = cString::sprintf("%s~%s", recDir.c_str(), timer->File());
|
|
timer->SetFile(*newFileName);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
//Set choosen path
|
|
cString newFileName;
|
|
if (path.size() > 0) {
|
|
std::replace(path.begin(), path.end(), '/', '~');
|
|
newFileName = cString::sprintf("%s~%s", path.c_str(), timer->File());
|
|
} else {
|
|
newFileName = event->Title();
|
|
}
|
|
timer->SetFile(*newFileName);
|
|
}
|
|
|
|
void cRecManager::DeleteTimer(int timerID) {
|
|
const cTimer *t;
|
|
#if VDRVERSNUM >= 20301
|
|
{
|
|
LOCK_TIMERS_READ;
|
|
t = Timers->Get(timerID);
|
|
}
|
|
#else
|
|
t = Timers.Get(timerID);
|
|
#endif
|
|
if (!t)
|
|
return;
|
|
DeleteTimer(t);
|
|
}
|
|
|
|
void cRecManager::DeleteTimer(const cEvent *event) {
|
|
if (!event)
|
|
return;
|
|
if (config.useRemoteTimers && pRemoteTimers) {
|
|
DeleteRemoteTimer(event);
|
|
} else {
|
|
DeleteLocalTimer(event);
|
|
}
|
|
}
|
|
|
|
void cRecManager::DeleteLocalTimer(const cEvent *event) {
|
|
const cTimer *t;
|
|
#if VDRVERSNUM >= 20301
|
|
{
|
|
LOCK_TIMERS_READ;
|
|
t = Timers->GetMatch(event);
|
|
}
|
|
#else
|
|
t = Timers.GetMatch(event);
|
|
#endif
|
|
if (!t)
|
|
return;
|
|
DeleteTimer(t);
|
|
}
|
|
|
|
void cRecManager::DeleteTimer(const cTimer *timer) {
|
|
#if VDRVERSNUM >= 20301
|
|
LOCK_TIMERS_WRITE;
|
|
cTimers* timers = Timers;
|
|
cTimer* t = timers->GetTimer(timer);
|
|
#else
|
|
cTimers* timers = &Timers;
|
|
cTimer* t = timers->GetTimer((cTimer*)timer);
|
|
#endif
|
|
if (!t)
|
|
return;
|
|
if (t->Recording()) {
|
|
t->Skip();
|
|
#if VDRVERSNUM >= 20301
|
|
cRecordControls::Process(timers, time(NULL));
|
|
#else
|
|
cRecordControls::Process(time(NULL));
|
|
#endif
|
|
}
|
|
isyslog("timer %s deleted", *t->ToDescr());
|
|
timers->Del(t, true);
|
|
timers->SetModified();
|
|
}
|
|
|
|
void cRecManager::DeleteRemoteTimer(const cEvent *event) {
|
|
RemoteTimers_GetMatch_v1_0 rtMatch;
|
|
rtMatch.event = event;
|
|
pRemoteTimers->Service("RemoteTimers::GetMatch-v1.0", &rtMatch);
|
|
if (rtMatch.timer) {
|
|
RemoteTimers_Timer_v1_0 rt;
|
|
rt.timer = rtMatch.timer;
|
|
isyslog("remotetimer %s deleted", *rt.timer->ToDescr());
|
|
if (!pRemoteTimers->Service("RemoteTimers::DelTimer-v1.0", &rt))
|
|
isyslog("remotetimer error");
|
|
RefreshRemoteTimers();
|
|
}
|
|
}
|
|
|
|
void cRecManager::SaveTimer(const cTimer *t, cTimer newTimerSettings) {
|
|
if (!t)
|
|
return;
|
|
|
|
#if VDRVERSNUM >= 20301
|
|
LOCK_TIMERS_WRITE;
|
|
cTimer *timer = Timers->GetTimer(t);
|
|
#else
|
|
cTimer *timer = Timers.GetTimer((cTimer*)t);
|
|
#endif
|
|
|
|
bool active = newTimerSettings.HasFlags(tfActive);
|
|
int prio = newTimerSettings.Priority();
|
|
int lifetime = newTimerSettings.Lifetime();
|
|
time_t day = newTimerSettings.Day();
|
|
int start = newTimerSettings.Start();
|
|
int stop = newTimerSettings.Stop();
|
|
std::string fileName = newTimerSettings.File();
|
|
|
|
timer->SetDay(day);
|
|
timer->SetStart(start);
|
|
timer->SetStop(stop);
|
|
timer->SetPriority(prio);
|
|
timer->SetLifetime(lifetime);
|
|
timer->SetFile(fileName.c_str());
|
|
|
|
if (timer->HasFlags(tfActive) && !active)
|
|
timer->ClrFlags(tfActive);
|
|
else if (!timer->HasFlags(tfActive) && active)
|
|
timer->SetFlags(tfActive);
|
|
|
|
#if VDRVERSNUM < 20300
|
|
timer->SetEventFromSchedule();
|
|
#endif
|
|
if (config.useRemoteTimers && pRemoteTimers) {
|
|
RemoteTimers_Timer_v1_0 rt;
|
|
rt.timer = timer;
|
|
if (!pRemoteTimers->Service("RemoteTimers::ModTimer-v1.0", &rt))
|
|
rt.timer = NULL;
|
|
RefreshRemoteTimers();
|
|
} else {
|
|
#if VDRVERSNUM >= 20301
|
|
Timers->SetModified();
|
|
#else
|
|
Timers.SetModified();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
bool cRecManager::IsRecorded(const cEvent *event) {
|
|
#if VDRVERSNUM >= 20301
|
|
LOCK_TIMERS_WRITE;
|
|
cTimer *timer = Timers->GetMatch(event);
|
|
#else
|
|
cTimer *timer = Timers.GetMatch(event);
|
|
#endif
|
|
if (!timer)
|
|
return false;
|
|
return timer->Recording();
|
|
}
|
|
|
|
cTVGuideTimerConflicts *cRecManager::CheckTimerConflict(void) {
|
|
cTVGuideTimerConflicts *conflictList = new cTVGuideTimerConflicts();
|
|
if (!epgSearchAvailable)
|
|
return conflictList;
|
|
Epgsearch_services_v1_1 *epgSearch = new Epgsearch_services_v1_1;
|
|
if (epgSearchPlugin->Service("Epgsearch-services-v1.1", epgSearch)) {
|
|
std::list<std::string> conflicts = epgSearch->handler->TimerConflictList();
|
|
int numConflicts = conflicts.size();
|
|
if (numConflicts == 0)
|
|
return conflictList;
|
|
for (std::list<std::string>::iterator it=conflicts.begin(); it != conflicts.end(); ++it) {
|
|
conflictList->AddConflict(*it);
|
|
}
|
|
}
|
|
delete epgSearch;
|
|
conflictList->CalculateConflicts();
|
|
return conflictList;
|
|
}
|
|
|
|
void cRecManager::CreateSeriesTimer(cTimer *seriesTimer) {
|
|
#if VDRVERSNUM < 20300
|
|
seriesTimer->SetEventFromSchedule();
|
|
#endif
|
|
if (config.useRemoteTimers && pRemoteTimers) {
|
|
RemoteTimers_Timer_v1_0 rt;
|
|
rt.timer = seriesTimer;
|
|
if (!pRemoteTimers->Service("RemoteTimers::NewTimer-v1.0", &rt))
|
|
isyslog("%s", *rt.errorMsg);
|
|
RefreshRemoteTimers();
|
|
} else {
|
|
#if VDRVERSNUM >= 20301
|
|
LOCK_TIMERS_WRITE;
|
|
cTimers* timers = Timers;
|
|
#else
|
|
cTimers* timers = &Timers;
|
|
#endif
|
|
timers->Add(seriesTimer);
|
|
timers->SetModified();
|
|
}
|
|
}
|
|
|
|
|
|
void cRecManager::ReadEPGSearchTemplates(std::vector<TVGuideEPGSearchTemplate> *epgTemplates) {
|
|
cString ConfigDir = cPlugin::ConfigDirectory("epgsearch");
|
|
cString epgsearchConf = "epgsearchtemplates.conf";
|
|
cString fileName = AddDirectory(*ConfigDir, *epgsearchConf);
|
|
if (access(fileName, F_OK) == 0) {
|
|
FILE *f = fopen(fileName, "r");
|
|
if (f) {
|
|
char *s;
|
|
cReadLine ReadLine;
|
|
while ((s = ReadLine.Read(f)) != NULL) {
|
|
char *p = strchr(s, '#');
|
|
if (p)
|
|
*p = 0;
|
|
stripspace(s);
|
|
try {
|
|
if (!isempty(s)) {
|
|
std::string templ = s;
|
|
int posID = templ.find_first_of(":");
|
|
int posName = templ.find_first_of(":", posID+1);
|
|
std::string name = templ.substr(posID+1, posName - posID - 1);
|
|
std::string templValue = templ.substr(posName);
|
|
TVGuideEPGSearchTemplate tmp;
|
|
tmp.name = name;
|
|
tmp.templValue = templValue;
|
|
epgTemplates->push_back(tmp);
|
|
}
|
|
} catch (...){}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const cEvent **cRecManager::PerformSearchTimerSearch(std::string epgSearchString, int &numResults) {
|
|
if (!epgSearchAvailable)
|
|
return NULL;
|
|
const cEvent **searchResults = NULL;
|
|
Epgsearch_services_v1_1 *epgSearch = new Epgsearch_services_v1_1;
|
|
if (epgSearchPlugin->Service("Epgsearch-services-v1.1", epgSearch)) {
|
|
std::list<std::string> results = epgSearch->handler->QuerySearch(epgSearchString);
|
|
numResults = results.size();
|
|
if (numResults > 0) {
|
|
searchResults = new const cEvent *[numResults];
|
|
const cSchedules *schedules;
|
|
#if VDRVERSNUM >= 20301
|
|
{
|
|
LOCK_SCHEDULES_READ;
|
|
schedules = Schedules;
|
|
}
|
|
#else
|
|
cSchedulesLock schedulesLock;
|
|
schedules = cSchedules::Schedules(schedulesLock);
|
|
#endif
|
|
const cEvent *event = NULL;
|
|
int index=0;
|
|
for (std::list<std::string>::iterator it=results.begin(); it != results.end(); ++it) {
|
|
try {
|
|
splitstring s(it->c_str());
|
|
std::vector<std::string> flds = s.split(':', 1);
|
|
int eventID = atoi(flds[1].c_str());
|
|
std::string channelID = flds[7];
|
|
tChannelID chanID = tChannelID::FromString(channelID.c_str());
|
|
const cChannel *channel;
|
|
#if VDRVERSNUM >= 20301
|
|
{
|
|
LOCK_CHANNELS_READ;
|
|
channel = Channels->GetByChannelID(chanID);
|
|
}
|
|
#else
|
|
channel = Channels.GetByChannelID(chanID);
|
|
#endif
|
|
if (channel) {
|
|
const cSchedule *Schedule = NULL;
|
|
Schedule = schedules->GetSchedule(channel);
|
|
event = Schedule->GetEvent(eventID);
|
|
if (event) {
|
|
searchResults[index] = event;
|
|
} else
|
|
return NULL;
|
|
} else
|
|
return NULL;
|
|
index++;
|
|
} catch (...){}
|
|
}
|
|
}
|
|
}
|
|
return searchResults;
|
|
}
|
|
|
|
const cEvent **cRecManager::PerformSearch(Epgsearch_searchresults_v1_0 data, int &numResults) {
|
|
if (epgSearchAvailable) {
|
|
if (epgSearchPlugin->Service("Epgsearch-searchresults-v1.0", &data)) {
|
|
cList<Epgsearch_searchresults_v1_0::cServiceSearchResult> *list = data.pResultList;
|
|
if (!list)
|
|
return NULL;
|
|
int numElements = list->Count();
|
|
const cEvent **searchResults = NULL;
|
|
if (numElements > 0) {
|
|
searchResults = new const cEvent *[numElements];
|
|
numResults = numElements;
|
|
int index = 0;
|
|
for (Epgsearch_searchresults_v1_0::cServiceSearchResult *r = list->First(); r ; r = list->Next(r)) {
|
|
searchResults[index] = r->event;
|
|
index++;
|
|
}
|
|
}
|
|
delete list;
|
|
return searchResults;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void cRecManager::GetSearchTimers(std::vector<cTVGuideSearchTimer> *searchTimer) {
|
|
if (!epgSearchAvailable) {
|
|
return;
|
|
}
|
|
Epgsearch_services_v1_1 *epgSearch = new Epgsearch_services_v1_1;
|
|
if (epgSearchPlugin->Service("Epgsearch-services-v1.1", epgSearch)) {
|
|
std::list<std::string> searchTimerList;
|
|
searchTimerList = epgSearch->handler->SearchTimerList();
|
|
for(std::list<std::string>::iterator it = searchTimerList.begin(); it != searchTimerList.end(); it++) {
|
|
cTVGuideSearchTimer timer;
|
|
timer.SetEPGSearchString(it->c_str());
|
|
if (timer.Parse())
|
|
searchTimer->push_back(timer);
|
|
}
|
|
}
|
|
std::sort(searchTimer->begin(), searchTimer->end());
|
|
}
|
|
|
|
void cRecManager::GetSearchExtCats(std::vector<std::string> *searchExtCats) {
|
|
if (!epgSearchAvailable) {
|
|
return;
|
|
}
|
|
Epgsearch_services_v1_1 *epgSearch = new Epgsearch_services_v1_1;
|
|
if (epgSearchPlugin->Service("Epgsearch-services-v1.1", epgSearch)) {
|
|
std::list<std::string> list;
|
|
list = epgSearch->handler->ExtEPGInfoList();
|
|
|
|
for (std::list<std::string>::iterator it = list.begin(); it != list.end(); it++) {
|
|
searchExtCats->push_back(*it);
|
|
}
|
|
}
|
|
}
|
|
|
|
void cRecManager::GetChannelGroups(std::vector<std::string> *channelGroups) {
|
|
if (!epgSearchAvailable) {
|
|
return;
|
|
}
|
|
Epgsearch_services_v1_1 *epgSearch = new Epgsearch_services_v1_1;
|
|
if (epgSearchPlugin->Service("Epgsearch-services-v1.1", epgSearch)) {
|
|
std::list<std::string> list;
|
|
list = epgSearch->handler->ChanGrpList();
|
|
|
|
for (std::list<std::string>::iterator it = list.begin(); it != list.end(); it++) {
|
|
channelGroups->push_back(*it);
|
|
}
|
|
}
|
|
std::sort(channelGroups->begin(), channelGroups->end());
|
|
}
|
|
|
|
void cRecManager::GetBlacklists(std::vector<std::string> *blacklists) {
|
|
if (!epgSearchAvailable) {
|
|
return;
|
|
}
|
|
Epgsearch_services_v1_1 *epgSearch = new Epgsearch_services_v1_1;
|
|
if (epgSearchPlugin->Service("Epgsearch-services-v1.1", epgSearch)) {
|
|
std::list<std::string> list;
|
|
list = epgSearch->handler->BlackList();
|
|
|
|
for (std::list<std::string>::iterator it = list.begin(); it != list.end(); it++) {
|
|
blacklists->push_back(*it);
|
|
}
|
|
}
|
|
}
|
|
|
|
int cRecManager::CreateSearchTimer(std::string epgSearchString) {
|
|
int timerID = -1;
|
|
if (!epgSearchAvailable)
|
|
return timerID;
|
|
Epgsearch_services_v1_1 *epgSearch = new Epgsearch_services_v1_1;
|
|
if (epgSearchPlugin->Service("Epgsearch-services-v1.1", epgSearch)) {
|
|
timerID = epgSearch->handler->AddSearchTimer(epgSearchString);
|
|
}
|
|
return timerID;
|
|
}
|
|
|
|
bool cRecManager::SaveSearchTimer(cTVGuideSearchTimer *searchTimer) {
|
|
if (!epgSearchAvailable)
|
|
return false;
|
|
Epgsearch_services_v1_1 *epgSearch = new Epgsearch_services_v1_1;
|
|
if (searchTimer->GetID() > -1) {
|
|
if (epgSearchPlugin->Service("Epgsearch-services-v1.1", epgSearch)) {
|
|
bool success = epgSearch->handler->ModSearchTimer(searchTimer->BuildSearchString());
|
|
if (success) {
|
|
esyslog("tvguide: search timer with id %d sucessfully modified", searchTimer->GetID());
|
|
return true;
|
|
} else {
|
|
esyslog("tvguide: error modifying search timer with id %d, build string %s", searchTimer->GetID(), searchTimer->BuildSearchString().c_str());
|
|
return false;
|
|
}
|
|
}
|
|
} else {
|
|
if (epgSearchPlugin->Service("Epgsearch-services-v1.1", epgSearch)) {
|
|
int timerID = epgSearch->handler->AddSearchTimer(searchTimer->BuildSearchString());
|
|
if (timerID >=0) {
|
|
esyslog("tvguide: search timer with id %d sucessfully created", timerID);
|
|
return true;
|
|
} else {
|
|
esyslog("tvguide: error creating search timer, build string %s", searchTimer->BuildSearchString().c_str());
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void cRecManager::DeleteSearchTimer(cTVGuideSearchTimer *searchTimer, bool delTimers) {
|
|
if (!epgSearchAvailable)
|
|
return;
|
|
int searchTimerID = searchTimer->GetID();
|
|
if (delTimers) {
|
|
cTimers* timers;
|
|
#if VDRVERSNUM >= 20301
|
|
{
|
|
LOCK_TIMERS_WRITE;
|
|
timers = Timers;
|
|
}
|
|
#else
|
|
timers = &Timers;
|
|
#endif
|
|
cTimer *timer = timers->First();
|
|
while (timer) {
|
|
if (!timer->Recording()) {
|
|
char* searchID = GetAuxValue(timer, "s-id");
|
|
if (searchID) {
|
|
if (searchTimerID == atoi(searchID)) {
|
|
cTimer* timerNext = timers->Next(timer);
|
|
DeleteTimer(timer);
|
|
timer = timerNext;
|
|
} else {
|
|
timer = timers->Next(timer);
|
|
}
|
|
free(searchID);
|
|
} else {
|
|
timer = timers->Next(timer);
|
|
}
|
|
} else {
|
|
timer = timers->Next(timer);
|
|
}
|
|
}
|
|
}
|
|
Epgsearch_services_v1_1 *epgSearch = new Epgsearch_services_v1_1;
|
|
if (epgSearchPlugin->Service("Epgsearch-services-v1.1", epgSearch)) {
|
|
bool success = epgSearch->handler->DelSearchTimer(searchTimerID);
|
|
if (success) {
|
|
esyslog("tvguide: search timer \"%s\" sucessfully deleted", searchTimer->GetSearchString().c_str());
|
|
} else {
|
|
esyslog("tvguide: error deleting search timer \"%s\"", searchTimer->GetSearchString().c_str());
|
|
}
|
|
}
|
|
}
|
|
|
|
void cRecManager::UpdateSearchTimers(void) {
|
|
if (epgSearchAvailable) {
|
|
Epgsearch_updatesearchtimers_v1_0 data;
|
|
data.showMessage = false;
|
|
epgSearchPlugin->Service("Epgsearch-updatesearchtimers-v1.0", &data);
|
|
}
|
|
}
|
|
|
|
// switchMode: 0 = switch, 1 = announce only, 2 = ask for switch
|
|
bool cRecManager::CreateSwitchTimer(const cEvent *event, cSwitchTimer switchTimer) {
|
|
if (epgSearchAvailable && event) {
|
|
Epgsearch_switchtimer_v1_0 data;
|
|
data.event = event;
|
|
data.mode = 1;
|
|
data.switchMinsBefore = switchTimer.switchMinsBefore;
|
|
data.announceOnly = switchTimer.switchMode;
|
|
data.success = false;
|
|
epgSearchPlugin->Service("Epgsearch-switchtimer-v1.0", &data);
|
|
cSwitchTimer *t = new cSwitchTimer(event);
|
|
SwitchTimers.Add(t);
|
|
return data.success;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void cRecManager::DeleteSwitchTimer(const cEvent *event) {
|
|
SwitchTimers.DeleteSwitchTimer(event);
|
|
if (epgSearchAvailable) {
|
|
Epgsearch_switchtimer_v1_0 data;
|
|
data.event = event;
|
|
data.mode = 2;
|
|
data.switchMinsBefore = 0;
|
|
data.announceOnly = 0;
|
|
data.success = false;
|
|
epgSearchPlugin->Service("Epgsearch-switchtimer-v1.0", &data);
|
|
}
|
|
}
|
|
|
|
const cRecording **cRecManager::SearchForRecordings(std::string searchString, int &numResults) {
|
|
|
|
const cRecording **matchingRecordings = NULL;
|
|
int num = 0;
|
|
numResults = 0;
|
|
|
|
#if VDRVERSNUM >= 20301
|
|
LOCK_RECORDINGS_READ;
|
|
const cRecordings* recordings = Recordings;
|
|
#else
|
|
const cRecordings* recordings = &Recordings;
|
|
#endif
|
|
|
|
for (const cRecording *recording = recordings->First(); recording; recording = recordings->Next(recording)) {
|
|
std::string s1 = recording->Name();
|
|
std::string s2 = searchString;
|
|
if (s1.empty() || s2.empty()) continue;
|
|
|
|
// tolerance for fuzzy searching: 90% of the shorter text length, but at least 1
|
|
int tolerance = std::max(1, (int)std::min(s1.size(), s2.size()) / 10);
|
|
|
|
bool match = FindIgnoreCase(s1, s2) >= 0 || FindIgnoreCase(s2, s1) >= 0;
|
|
|
|
if (!match) {
|
|
AFUZZY af = { NULL, NULL, NULL, NULL, NULL, NULL, { 0 }, { 0 }, 0, 0, 0, 0, 0, 0 };
|
|
if (s1.size() > 32) s1 = s1.substr(0, 32);
|
|
afuzzy_init(s1.c_str(), tolerance, 0, &af);
|
|
/* Checking substring */
|
|
int res = afuzzy_checkSUB(s2.c_str(), &af);
|
|
afuzzy_free(&af);
|
|
match = (res > 0);
|
|
}
|
|
|
|
if (!match) {
|
|
AFUZZY af = { NULL, NULL, NULL, NULL, NULL, NULL, { 0 }, { 0 }, 0, 0, 0, 0, 0, 0 };
|
|
if (s2.size() > 32) s2 = s2.substr(0, 32);
|
|
afuzzy_init(s2.c_str(), tolerance, 0, &af);
|
|
/* Checking substring */
|
|
int res = afuzzy_checkSUB(s1.c_str(), &af);
|
|
afuzzy_free(&af);
|
|
match = (res > 0);
|
|
}
|
|
|
|
if (match) {
|
|
matchingRecordings = (const cRecording **)realloc(matchingRecordings, (num + 1) * sizeof(cRecording *));
|
|
matchingRecordings[num++] = recording;
|
|
}
|
|
}
|
|
if (num > 0) {
|
|
qsort(matchingRecordings, num, sizeof(cRecording *), CompareRecording);
|
|
numResults = num;
|
|
return matchingRecordings;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
const cEvent **cRecManager::LoadReruns(const cEvent *event, int &numResults) {
|
|
if (epgSearchAvailable && !isempty(event->Title())) {
|
|
Epgsearch_searchresults_v1_0 data;
|
|
std::string strQuery = event->Title();
|
|
if (config.useSubtitleRerun > 0) {
|
|
if (config.useSubtitleRerun == 2 || !isempty(event->ShortText()))
|
|
strQuery += "~";
|
|
if (!isempty(event->ShortText()))
|
|
strQuery += event->ShortText();
|
|
data.useSubTitle = true;
|
|
} else {
|
|
data.useSubTitle = false;
|
|
}
|
|
data.query = (char *)strQuery.c_str();
|
|
data.mode = 0;
|
|
data.channelNr = 0;
|
|
data.useTitle = true;
|
|
data.useDescription = false;
|
|
|
|
if (epgSearchPlugin->Service("Epgsearch-searchresults-v1.0", &data)) {
|
|
cList<Epgsearch_searchresults_v1_0::cServiceSearchResult>* list = data.pResultList;
|
|
if (!list)
|
|
return NULL;
|
|
const cEvent **searchResults = NULL;
|
|
int numElements = list->Count();
|
|
if (numElements > 0) {
|
|
searchResults = new const cEvent *[numElements];
|
|
int index = 0;
|
|
for (Epgsearch_searchresults_v1_0::cServiceSearchResult *r = list->First(); r; r = list->Next(r)) {
|
|
if ((event->ChannelID() == r->event->ChannelID()) && (event->StartTime() == r->event->StartTime()))
|
|
continue;
|
|
searchResults[index] = r->event;
|
|
index++;
|
|
}
|
|
delete list;
|
|
numResults = index;
|
|
return searchResults;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void cRecManager::GetFavorites(std::vector<cTVGuideSearchTimer> *favorites) {
|
|
if (!epgSearchAvailable) {
|
|
return;
|
|
}
|
|
Epgsearch_services_v1_1 *epgSearch = new Epgsearch_services_v1_1;
|
|
if (epgSearchPlugin->Service("Epgsearch-services-v1.1", epgSearch)) {
|
|
std::list<std::string> searchTimerList;
|
|
searchTimerList = epgSearch->handler->SearchTimerList();
|
|
for(std::list<std::string>::iterator it = searchTimerList.begin(); it != searchTimerList.end(); it++) {
|
|
cTVGuideSearchTimer timer;
|
|
timer.SetEPGSearchString(it->c_str());
|
|
if (timer.Parse()) {
|
|
if (timer.UseInFavorites())
|
|
favorites->push_back(timer);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
const cEvent **cRecManager::WhatsOnNow(bool nowOrNext, int &numResults) {
|
|
std::vector<const cEvent*> tmpResults;
|
|
#if VDRVERSNUM >= 20301
|
|
LOCK_CHANNELS_READ;
|
|
const cChannels* channels = Channels;
|
|
LOCK_SCHEDULES_READ;
|
|
const cSchedules* schedules = Schedules;
|
|
#else
|
|
cChannels* channels = &Channels;
|
|
cSchedulesLock schedulesLock;
|
|
const cSchedules *schedules = cSchedules::Schedules(schedulesLock);
|
|
#endif
|
|
const cChannel *startChannel = NULL, *stopChannel = NULL;
|
|
if (config.favLimitChannels) {
|
|
startChannel = channels->GetByNumber(config.favStartChannel);
|
|
stopChannel = channels->GetByNumber(config.favStopChannel);
|
|
}
|
|
if (!startChannel)
|
|
startChannel = channels->First();
|
|
|
|
for (const cChannel *channel = startChannel; channel; channel = channels->Next(channel)) {
|
|
if (channel->GroupSep()) continue;
|
|
const cSchedule *Schedule = schedules->GetSchedule(channel);
|
|
if (!Schedule) continue;
|
|
|
|
const cEvent *event = NULL;
|
|
if (nowOrNext)
|
|
event = Schedule->GetPresentEvent();
|
|
else
|
|
event = Schedule->GetFollowingEvent();
|
|
if (event) {
|
|
tmpResults.push_back(event);
|
|
}
|
|
if (stopChannel && (stopChannel->Number() <= channel->Number()))
|
|
break;
|
|
}
|
|
numResults = tmpResults.size();
|
|
const cEvent **results = new const cEvent *[numResults];
|
|
for (int i=0; i<numResults; i++) {
|
|
results[i] = tmpResults[i];
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
const cEvent **cRecManager::UserDefinedTime(int userTime, int &numResults) {
|
|
std::vector<const cEvent*> tmpResults;
|
|
int favTime = 0;
|
|
if (userTime == 1) {
|
|
favTime = config.favTime1;
|
|
} else if (userTime == 2) {
|
|
favTime = config.favTime2;
|
|
} else if (userTime == 3) {
|
|
favTime = config.favTime3;
|
|
} else if (userTime == 4) {
|
|
favTime = config.favTime4;
|
|
}
|
|
|
|
time_t now = time(0);
|
|
tm *midn = localtime(&now);
|
|
midn->tm_sec = 0;
|
|
midn->tm_min = 0;
|
|
midn->tm_hour = 0;
|
|
time_t midnight = mktime(midn);
|
|
int hours = favTime/100;
|
|
int mins = favTime - hours * 100;
|
|
time_t searchTime = midnight + hours*60*60 + mins*60;
|
|
if (searchTime < now)
|
|
searchTime += 24*60*60;
|
|
|
|
#if VDRVERSNUM >= 20301
|
|
LOCK_CHANNELS_READ;
|
|
const cChannels* channels = Channels;
|
|
LOCK_SCHEDULES_READ;
|
|
const cSchedules* schedules = Schedules;
|
|
#else
|
|
cChannels* channels = &Channels;
|
|
cSchedulesLock schedulesLock;
|
|
const cSchedules *schedules = cSchedules::Schedules(schedulesLock);
|
|
#endif
|
|
const cChannel *startChannel = NULL, *stopChannel = NULL;
|
|
if (config.favLimitChannels) {
|
|
startChannel = channels->GetByNumber(config.favStartChannel);
|
|
stopChannel = channels->GetByNumber(config.favStopChannel);
|
|
}
|
|
if (!startChannel)
|
|
startChannel = channels->First();
|
|
|
|
for (const cChannel *channel = startChannel; channel; channel = channels->Next(channel)) {
|
|
if (channel->GroupSep()) continue;
|
|
const cSchedule *Schedule = schedules->GetSchedule(channel);
|
|
if (!Schedule) continue;
|
|
const cEvent *event = Schedule->GetEventAround(searchTime);
|
|
if (!event) continue;
|
|
//if event is more or less over (only 15mns left), take next
|
|
if ((event->EndTime() - searchTime) < 15*60) {
|
|
event = Schedule->Events()->Next(event);
|
|
}
|
|
if (event)
|
|
tmpResults.push_back(event);
|
|
if (stopChannel && (stopChannel->Number() <= channel->Number()))
|
|
break;
|
|
}
|
|
|
|
numResults = tmpResults.size();
|
|
const cEvent **results = new const cEvent *[numResults];
|
|
for (int i=0; i<numResults; i++) {
|
|
results[i] = tmpResults[i];
|
|
}
|
|
return results;
|
|
}
|