summaryrefslogtreecommitdiff
path: root/xmltv2vdr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xmltv2vdr.cpp')
-rw-r--r--xmltv2vdr.cpp1107
1 files changed, 281 insertions, 826 deletions
diff --git a/xmltv2vdr.cpp b/xmltv2vdr.cpp
index 9984422..c5a2142 100644
--- a/xmltv2vdr.cpp
+++ b/xmltv2vdr.cpp
@@ -6,841 +6,195 @@
*/
#include <vdr/plugin.h>
-#include <string.h>
-#include <time.h>
-#include <sys/wait.h>
-#include <sys/ioctl.h>
-#include <stdarg.h>
-#include <pwd.h>
-#include "xmltv2vdr.h"
-#include "parse.h"
-#include "extpipe.h"
-#include "setup.h"
-
-#if __GNUC__ > 3
-#define UNUSED(v) UNUSED_ ## v __attribute__((unused))
-#else
-#define UNUSED(x) x
-#endif
-
-// -------------------------------------------------------------
-
-cEPGChannel::cEPGChannel(const char *Name, bool InUse)
-{
- name=strdup(Name);
- inuse=InUse;
-}
-
-cEPGChannel::~cEPGChannel()
-{
- if (name) free((void *) name);
-}
+#include <vdr/videodir.h>
+#include <unistd.h>
+#include <getopt.h>
-int cEPGChannel::Compare(const cListObject &ListObject) const
-{
- cEPGChannel *epgchannel= (cEPGChannel *) &ListObject;
- return strcmp(name,epgchannel->Name());
-}
+#include "setup.h"
+#include "xmltv2vdr.h"
// -------------------------------------------------------------
-cEPGExecutor::cEPGExecutor(cEPGSources *Sources) : cThread("xmltv2vdr importer")
+cEPGHandler::cEPGHandler(const char *EpgFile, cEPGSources *Sources, cEPGMappings *Maps,
+ cTEXTMappings *Texts)
{
- sources=Sources;
- textmappings=NULL;
epall=false;
+ epgfile=EpgFile;
+ maps=Maps;
+ sources=Sources;
+ import = new cImport(NULL,Maps,Texts);
}
-void cEPGExecutor::Action()
+cEPGHandler::~cEPGHandler()
{
- if (!sources) return;
- int ret=0;
- for (cEPGSource *epgs=sources->First(); epgs; epgs=sources->Next(epgs))
- {
- int retries=0;
- while (retries<=2)
- {
- ret=epgs->Execute(*this);
- if ((ret>0) && (ret<126) && (retries<2))
- {
- epgs->Dlog("waiting 60 seconds");
- int l=0;
- while (l<300)
- {
- struct timespec req;
- req.tv_sec=0;
- req.tv_nsec=200000000; // 200ms
- nanosleep(&req,NULL);
- if (!Running())
- {
- epgs->Ilog("request to stop from vdr");
- return;
- }
- l++;
- }
- retries++;
- }
- else
- {
- break;
- }
- }
- if (retries>=2) epgs->Elog("skipping after %i retries",retries);
- if (!ret) break; // TODO: check if we must execute second/third source!
- }
- if (!ret && epall && textmappings)
- {
- struct passwd pwd,*pwdbuf;
- char buf[1024];
- getpwuid_r(getuid(),&pwd,buf,sizeof(buf),&pwdbuf);
- if (pwdbuf)
- {
- char *epdir;
- if (asprintf(&epdir,"%s/.eplists/lists",pwdbuf->pw_dir)!=-1)
- {
- if (!access(epdir,R_OK))
- {
- int retries=0;
- while (retries<=2)
- {
-
- if (!cParse::AddSeasonEpisode2TimerChannels(epdir,textmappings))
- {
- dsyslog("waiting 60 seconds");
- retries++;
- }
- else
- {
- break;
- }
- }
- }
- free(epdir);
- }
- }
- }
- if (!ret) cSchedules::Cleanup(true);
+ if (import) delete import;
}
-
-
-// -------------------------------------------------------------
-
-cEPGSource::cEPGSource(const char *Name, const char *ConfDir, cEPGMappings *Maps, cTEXTMappings *Texts)
+bool cEPGHandler::IgnoreChannel(const cChannel* Channel)
{
- dsyslog("xmltv2vdr: '%s' added epgsource",Name);
- name=strdup(Name);
- confdir=strdup(ConfDir);
- pin=NULL;
- Log=NULL;
- loglen=0;
- usepipe=false;
- needpin=false;
- running=false;
- daysinadvance=0;
- lastexec=(time_t) 0;
- ready2parse=ReadConfig();
- parse=new cParse(this, Maps, Texts);
- Dlog("is%sready2parse",(ready2parse && parse) ? " " : " not ");
+ if (!maps) return false;
+ if (!Channel) return false;
+ return maps->IgnoreChannel(Channel);
}
-cEPGSource::~cEPGSource()
+bool cEPGHandler::SetContents(cEvent* UNUSED(Event), uchar* UNUSED(Contents))
{
- dsyslog("xmltv2vdr: '%s' epgsource removed",name);
- free((void *) name);
- free((void *) confdir);
- if (pin) free((void *) pin);
- if (Log) free((void *) Log);
- if (parse) delete parse;
+ return false;
}
-bool cEPGSource::ReadConfig()
+bool cEPGHandler::SetDescription(cEvent* Event, const char* Description)
{
- char *fname=NULL;
- if (asprintf(&fname,"%s/%s",EPGSOURCES,name)==-1)
- {
- Elog("out of memory");
- return false;
- }
- FILE *f=fopen(fname,"r");
- if (!f)
- {
- Elog("cannot read config file %s",fname);
- free(fname);
- return false;
- }
- Dlog("reading source config");
- size_t lsize;
- char *line=NULL;
- int linenr=1;
- while (getline(&line,&lsize,f)!=-1)
- {
- if (linenr==1)
- {
- if (!strncmp(line,"pipe",4))
- {
- Dlog("is providing data through a pipe");
- usepipe=true;
- }
- else
- {
- Dlog("is providing data through a file");
- usepipe=false;
- }
- char *ndt=strchr(line,';');
- if (ndt)
- {
- *ndt=0;
- ndt++;
- char *pn=strchr(ndt,';');
- if (pn)
- {
- *pn=0;
- pn++;
- }
- /*
- newdatatime=atoi(ndt);
- if (!newdatatime) Dlog("updates source data @%02i:%02i",1,2);
- */
- if (pn)
- {
- pn=compactspace(pn);
- if (pn[0]=='1')
- {
- Dlog("is needing a pin");
- needpin=true;
- }
- }
- }
- }
- if (linenr==2)
- {
- char *semicolon=strchr(line,';');
- if (semicolon)
- {
- // backward compatibility
- *semicolon=0;
- semicolon++;
- daysmax=atoi(semicolon);
- }
- else
- {
- daysmax=atoi(line);
- }
- Dlog("daysmax=%i",daysmax);
- }
- if (linenr>2)
- {
- // channels
- char *semicolon=strchr(line,';');
- if (semicolon) *semicolon=0;
- char *lf=strchr(line,10);
- if (lf) *lf=0;
- char *cname=line;
- if (line[0]=='*')
- {
- // backward compatibility
- cname++;
- }
- if (!strchr(cname,' ') && (strlen(cname)>0))
- {
- cEPGChannel *epgchannel= new cEPGChannel(cname,false);
- if (epgchannel) channels.Add(epgchannel);
- }
- }
- linenr++;
- }
- if (line) free(line);
- channels.Sort();
- fclose(f);
- free(fname);
+ if (!Event) return false;
+ if (!maps) return false;
+ if (!import) return false;
- /* --------------- */
-
- if (asprintf(&fname,"%s/%s",confdir,name)==-1)
- {
- Elog("out of memory");
- return false;
- }
- f=fopen(fname,"r+");
- if (!f)
+ bool special_epall_timer_handling=false;
+ if (!maps->ProcessChannel(Event->ChannelID()))
{
- if (errno!=ENOENT)
- {
- Elog("cannot read config file %s",fname);
- free(fname);
- return true;
- }
- /* still no config? -> ok */
- free(fname);
- return true;
+ if (!epall) return false;
+ if (!Event->HasTimer()) return false;
+ if (!Event->ShortText()) return false;
+ special_epall_timer_handling=true;
}
- Dlog("reading plugin config");
- line=NULL;
- linenr=1;
- while (getline(&line,&lsize,f)!=-1)
- {
- if ((linenr==1) && (needpin))
- {
- char *lf=strchr(line,10);
- if (lf) *lf=0;
- if (strcmp(line,"#no pin"))
- {
- ChangePin(line);
- Dlog("pin set");
- }
- }
- if (linenr==2)
- {
- daysinadvance=atoi(line);
- Dlog("daysinadvance=%i",daysinadvance);
- }
- if (linenr>2)
- {
- // channels
- char *lf=strchr(line,10);
- if (lf) *lf=0;
- for (int x=0; x<channels.Count(); x++)
- {
- if (!strcmp(line,channels.Get(x)->Name()))
- {
- channels.Get(x)->SetUsage(true);
- break;
- }
- }
- }
- linenr++;
- }
- if (line) free(line);
- channels.Sort();
- fclose(f);
- free(fname);
-
- return true;
-}
+ int Flags=0;
+ const char *ChannelID;
-int cEPGSource::ReadOutput(char *&result, size_t &l)
-{
- int ret=0;
- char *fname=NULL;
- if (asprintf(&fname,"%s/%s.xmltv",EPGSOURCES,name)==-1)
+ if (special_epall_timer_handling)
{
- Elog("out of memory");
- return 134;
+ cChannel *chan=Channels.GetByChannelID(Event->ChannelID());
+ if (!chan) return false;
+ Flags=USE_SEASON;
+ ChannelID=chan->Name();
}
- Dlog("reading from '%s'",fname);
-
- int fd=open(fname,O_RDONLY);
- if (fd==-1)
- {
- Elog("failed to open '%s'",fname);
- free(fname);
- return 157;
- }
-
- struct stat statbuf;
- if (fstat(fd,&statbuf)==-1)
- {
- Elog("failed to stat '%s'",fname);
- close(fd);
- free(fname);
- return 157;
- }
- l=statbuf.st_size;
- result=(char *) malloc(l+1);
- if (!result)
- {
- close(fd);
- free(fname);
- Elog("out of memory");
- return 134;
- }
- if (read(fd,result,statbuf.st_size)!=statbuf.st_size)
+ else
{
- Elog("failed to read '%s'",fname);
- ret=149;
- free(result);
- result=NULL;
+ cEPGMapping *map=maps->GetMap(Event->ChannelID());
+ if (!map) return false;
+ Flags=map->Flags();
+ ChannelID=map->ChannelName();
}
- close(fd);
- free(fname);
- return ret;
-}
-
-int cEPGSource::Execute(cEPGExecutor &myExecutor)
-{
- if (!ready2parse) return false;
- if (!parse) return false;
- char *r_out=NULL;
- char *r_err=NULL;
- int l_out=0;
- int l_err=0;
- int ret=0;
- if ((Log) && (lastexec))
+ cXMLTVEvent *xevent=import->SearchXMLTVEvent(epgfile,ChannelID,Event);
+ if (!xevent)
{
- free(Log);
- Log=NULL;
- loglen=0;
+ if (!epall) return false;
+ xevent=import->AddXMLTVEvent(epgfile,ChannelID,Event,Description);
+ if (!xevent) return false;
}
- char *cmd=NULL;
- if (asprintf(&cmd,"%s %i '%s'",name,daysinadvance,pin ? pin : "")==-1)
- {
- Elog("out of memory");
- return 134;
- }
+ bool update=false;
+ if (!xevent->EITEventID()) update=true;
+ if (!xevent->EITDescription() && Description) update=true;
+ if (xevent->EITDescription() && Description &&
+ strcasecmp(xevent->EITDescription(),Description)) update=true;
- for (int x=0; x<channels.Count(); x++)
- {
- if (channels.Get(x)->InUse())
- {
- int len=strlen(cmd);
- int clen=strlen(channels.Get(x)->Name());
- char *ncmd=(char *) realloc(cmd,len+clen+5);
- if (!ncmd)
- {
- free(cmd);
- Elog("out of memory");
- return 134;
- }
- cmd=ncmd;
- strcat(cmd," ");
- strcat(cmd,channels.Get(x)->Name());
- strcat(cmd," ");
- }
- }
- char *pcmd=strdup(cmd);
- if (pcmd)
- {
- char *pa=strchr(pcmd,'\'');
- char *pe=strchr(pa+1,'\'');
- if (pa && pe)
- {
- pa++;
- for (char *c=pa; c<pe; c++)
- {
- if (c==pa)
- {
- *c='X';
- }
- else
- {
- *c='@';
- }
- }
- pe=pcmd;
- while (*pe)
- {
- if (*pe=='@')
- {
- memmove(pe,pe+1,strlen(pe));
- }
- else
- {
- pe++;
- }
- }
- Ilog("%s",pcmd);
- }
- free(pcmd);
- }
- cExtPipe p;
- if (!p.Open(cmd))
+ if (update)
{
- free(cmd);
- Elog("failed to open pipe");
- return 141;
+ import->UpdateXMLTVEvent(epgfile,NULL,xevent->Source(),
+ xevent->EventID(),Event->EventID(),Description);
}
- free(cmd);
- Dlog("executing epgsource");
- running=true;
- int fdsopen=2;
- while (fdsopen>0)
- {
- struct pollfd fds[2];
- fds[0].fd=p.Out();
- fds[0].events=POLLIN;
- fds[1].fd=p.Err();
- fds[1].events=POLLIN;
- if (poll(fds,2,500)>=0)
- {
- if (fds[0].revents & POLLIN)
- {
- int n;
- if (ioctl(p.Out(),FIONREAD,&n)<0)
- {
- n=1;
- }
- r_out=(char *) realloc(r_out, l_out+n+1);
- int l=read(p.Out(),r_out+l_out,n);
- if (l>0)
- {
- l_out+=l;
- }
- }
- if (fds[1].revents & POLLIN)
- {
- int n;
- if (ioctl(p.Err(),FIONREAD,&n)<0)
- {
- n=1;
- }
- r_err=(char *) realloc(r_err, l_err+n+1);
- int l=read(p.Err(),r_err+l_err,n);
- if (l>0)
- {
- l_err+=l;
- }
- }
- if (fds[0].revents & POLLHUP)
- {
- fdsopen--;
- }
- if (fds[1].revents & POLLHUP)
- {
- fdsopen--;
- }
- if (!myExecutor.StillRunning())
- {
- int status;
- p.Close(status);
- if (r_out) free(r_out);
- if (r_err) free(r_err);
- Ilog("request to stop from vdr");
- running=false;
- return 0;
- }
- }
- else
- {
- Elog("failed polling");
- break;
- }
+ bool ret=import->PutEvent(sources->GetSource(xevent->Source()),NULL,
+ (cSchedule *) Event->Schedule(),
+ Event,xevent,Flags,IMPORT_DESCRIPTION);
+ delete xevent;
+ if (!ret) {
+ dsyslog("xmltv2vdr: failed to put event description!");
}
- if (r_out) r_out[l_out]=0;
- if (r_err) r_err[l_err]=0;
-
- if (usepipe)
- {
- int status;
- if (p.Close(status)>0)
- {
- int returncode=WEXITSTATUS(status);
- if ((!returncode) && (r_out))
- {
- //Dlog("xmltv2vdr: '%s' parsing output");
- Dlog("parsing output");
- ret=parse->Process(myExecutor,r_out,l_out);
- }
- else
- {
- Elog("epgsource returned %i",returncode);
- ret=returncode;
- }
- }
- else
- {
- Elog("failed to execute");
- ret=126;
- }
- }
- else
- {
- int status;
- if (p.Close(status)>0)
- {
- int returncode=WEXITSTATUS(status);
- if (!returncode)
- {
- size_t l;
- char *result=NULL;
- ret=ReadOutput(result,l);
- if ((!ret) && (result))
- {
- ret=parse->Process(myExecutor,result,l);
- }
- if (result) free(result);
- }
- else
- {
- Elog("epgsource returned %i",returncode);
- ret=returncode;
- }
- }
- }
- if (r_out) free(r_out);
- if (!ret) lastexec=time(NULL);
- if (r_err)
- {
- char *saveptr;
- char *pch=strtok_r(r_err,"\n",&saveptr);
- char *last=(char *) "";
- while (pch)
- {
- if (strcmp(last,pch))
- {
- Elog("%s",pch);
- last=pch;
- }
- pch=strtok_r(NULL,"\n",&saveptr);
- }
- free(r_err);
- }
- running=false;
return ret;
}
-void cEPGSource::ChangeChannelSelection(int *Selection)
+bool cEPGHandler::SetParentalRating(cEvent* UNUSED(Event), int UNUSED(ParentalRating))
{
- for (int i=0; i<channels.Count(); i++)
- {
- channels.Get(i)->SetUsage(Selection[i]);
- }
-}
-
-void cEPGSource::Store(void)
-{
- char *fname1=NULL;
- char *fname2=NULL;
- if (asprintf(&fname1,"%s/%s",confdir,name)==-1) return;
- if (asprintf(&fname2,"%s/%s.new",confdir,name)==-1)
- {
- Elog("out of memory");
- free(fname1);
- return;
- }
-
- FILE *w=fopen(fname2,"w+");
- if (!w)
- {
- Elog("cannot create %s",fname2);
- unlink(fname2);
- free(fname1);
- free(fname2);
- return;
- }
-
- if (pin)
- {
- fprintf(w,"%s\n",pin);
- }
- else
- {
- fprintf(w,"#no pin\n");
- }
- fprintf(w,"%i\n",DaysInAdvance());
- for (int i=0; i<ChannelList()->Count(); i++)
- {
- if (ChannelList()->Get(i)->InUse())
- {
- fprintf(w,"%s\n",ChannelList()->Get(i)->Name());
- }
- }
- fclose(w);
-
- struct stat statbuf;
- if (stat(confdir,&statbuf)!=-1)
- {
- if (chown(fname2,statbuf.st_uid,statbuf.st_gid)) {}
- }
-
- rename(fname2,fname1);
- free(fname1);
- free(fname2);
+ return false;
}
-void cEPGSource::add2Log(const char Prefix, const char *line)
+bool cEPGHandler::SetShortText(cEvent* Event, const char* UNUSED(ShortText))
{
- if (!line) return;
+ if (!Event) return false;
+ if (!maps) return false;
+ if (!import) return false;
- struct tm tm;
- time_t now=time(NULL);
- localtime_r(&now,&tm);
- char dt[30];
- strftime(dt,sizeof(dt)-1,"%H:%M ",&tm);
+ if (!maps->ProcessChannel(Event->ChannelID())) return false;
- loglen+=strlen(line)+3+strlen(dt);
- char *nptr=(char *) realloc(Log,loglen);
- if (nptr)
- {
- if (!Log) nptr[0]=0;
- Log=nptr;
- char prefix[2];
- prefix[0]=Prefix;
- prefix[1]=0;
- strcat(Log,prefix);
- strcat(Log,dt);
- strcat(Log,line);
- strcat(Log,"\n");
- Log[loglen-1]=0;
- }
-}
+ cEPGMapping *map=maps->GetMap(Event->ChannelID());
+ if (!map) return false;
-void cEPGSource::Elog(const char *format, ...)
-{
- va_list ap;
- char fmt[255];
- if (snprintf(fmt,sizeof(fmt),"xmltv2vdr '%s' ERROR %s",name,format)==-1) return;
- va_start(ap, format);
- char *ptr;
- if (vasprintf(&ptr,fmt,ap)==-1) return;
- va_end(ap);
- esyslog(ptr);
- add2Log('E',ptr+19+strlen(name));
- free(ptr);
-}
+ cXMLTVEvent *xevent=import->SearchXMLTVEvent(epgfile,map->ChannelName(),Event);
+ if (!xevent) return false;
-void cEPGSource::Dlog(const char *format, ...)
-{
- va_list ap;
- char fmt[255];
- if (snprintf(fmt,sizeof(fmt),"xmltv2vdr '%s' %s",name,format)==-1) return;
- va_start(ap, format);
- char *ptr;
- if (vasprintf(&ptr,fmt,ap)==-1) return;
- va_end(ap);
- dsyslog(ptr);
- add2Log('D',ptr+13+strlen(name));
- free(ptr);
-}
+ if (!xevent->EITEventID()) import->UpdateXMLTVEvent(epgfile,NULL,xevent->Source(),
+ xevent->EventID(),Event->EventID());
-void cEPGSource::Ilog(const char *format, ...)
-{
- va_list ap;
- char fmt[255];
- if (snprintf(fmt,sizeof(fmt),"xmltv2vdr '%s' %s",name,format)==-1) return;
- va_start(ap, format);
- char *ptr;
- if (vasprintf(&ptr,fmt,ap)==-1) return;
- va_end(ap);
- isyslog(ptr);
- add2Log('I',ptr+13+strlen(name));
- free(ptr);
+ bool ret=import->PutEvent(sources->GetSource(xevent->Source()),NULL,
+ (cSchedule *) Event->Schedule(),Event,xevent,
+ map->Flags(),IMPORT_SHORTTEXT);
+ delete xevent;
+ if (!ret) {
+ dsyslog("xmltv2vdr: failed to put event shorttext!");
+ }
+ return ret;
}
// -------------------------------------------------------------
-bool cPluginXmltv2vdr::epgsourceexists(const char *name)
+cEPGTimer::cEPGTimer(const char *EpgFile, cEPGSources *Sources, cEPGMappings *Maps,
+ cTEXTMappings *Texts) : cThread("xmltv2vdr timer thread")
{
- if (!epgsources.Count()) return false;
- for (cEPGSource *epgs=epgsources.First(); epgs; epgs=epgsources.Next(epgs))
- {
- if (!strcmp(epgs->Name(),name)) return true;
- }
- return false;
+ epgfile=EpgFile;
+ sources=Sources;
+ maps=Maps;
+ import = new cImport(NULL,Maps,Texts);
}
-void cPluginXmltv2vdr::removeepgmappings()
+void cEPGTimer::Action()
{
- cEPGMapping *maps;
- while ((maps=epgmappings.Last())!=NULL)
- {
- epgmappings.Del(maps);
- }
-}
+ struct stat statbuf;
+ if (stat(epgfile,&statbuf)==-1) return; // no database? -> exit immediately
+ if (!statbuf.st_size) return; // no database? -> exit immediately
-void cPluginXmltv2vdr::removetextmappings()
-{
- cTEXTMapping *maps;
- while ((maps=textmappings.Last())!=NULL)
+ cSchedulesLock *schedulesLock = new cSchedulesLock(true,2000); // wait up to 2 secs for lock!
+ const cSchedules *schedules = cSchedules::Schedules(*schedulesLock);
+ if (!schedules)
{
- textmappings.Del(maps);
+ delete schedulesLock;
+ return;
}
-}
-void cPluginXmltv2vdr::removeepgsources()
-{
- cEPGSource *epgs;
- while ((epgs=epgsources.Last())!=NULL)
+ for (cTimer *Timer = Timers.First(); Timer; Timer = Timers.Next(Timer))
{
- epgsources.Del(epgs);
- }
-}
+ const cEvent *event=Timer->Event();
+ if (!event) continue;
+ if (!event->ShortText()) continue; // no short text -> no episode
+ if (maps->ProcessChannel(event->ChannelID())) continue; // already processed by xmltv2vdr
-cEPGMapping *cPluginXmltv2vdr::EPGMapping(const char *ChannelName)
-{
- if (!ChannelName) return NULL;
- if (!epgmappings.Count()) return NULL;
- for (cEPGMapping *maps=epgmappings.First(); maps; maps=epgmappings.Next(maps))
- {
- if (!strcmp(maps->ChannelName(),ChannelName)) return maps;
- }
- return NULL;
-}
+ cChannel *chan=Channels.GetByChannelID(event->ChannelID());
+ if (!chan) continue;
+ const char *ChannelID=chan->Name();
-cTEXTMapping *cPluginXmltv2vdr::TEXTMapping(const char *Name)
-{
- if (!textmappings.Count()) return NULL;
- for (cTEXTMapping *textmap=textmappings.First(); textmap; textmap=textmappings.Next(textmap))
- {
- if (!strcmp(textmap->Name(),Name)) return textmap;
- }
- return NULL;
-}
+ cXMLTVEvent *xevent=import->SearchXMLTVEvent(epgfile,ChannelID,event);
+ if (!xevent)
+ {
+ xevent=import->AddXMLTVEvent(epgfile,ChannelID,event,event->Description());
+ if (!xevent) continue;
+ }
-void cPluginXmltv2vdr::ReadInEPGSources(bool Reload)
-{
- if (Reload) removeepgsources();
- DIR *dir=opendir(EPGSOURCES);
- if (!dir) return;
- struct dirent *dirent;
- while (dirent=readdir(dir))
- {
- if (strchr(&dirent->d_name[0],'.')) continue;
- if (!epgsourceexists(dirent->d_name))
+ int Flags=USE_SEASON;
+
+ cSchedule* schedule = (cSchedule *) schedules->GetSchedule(chan,false);
+ if (schedule)
{
- char *path=NULL;
- if (asprintf(&path,"%s/%s",EPGSOURCES,dirent->d_name)!=-1)
- {
- if (access(path,R_OK)!=-1)
- {
- int fd=open(path,O_RDONLY);
- if (fd!=-1)
- {
- char id[5];
- if (read(fd,id,4)!=4)
- {
- esyslog("xmltv2vdr: cannot read config file '%s'",dirent->d_name);
- }
- else
- {
- id[4]=0;
- if (!strcmp(id,"file") || !strcmp(id,"pipe"))
- {
- epgsources.Add(new cEPGSource(dirent->d_name,confdir,&epgmappings,&textmappings));
- }
- else
- {
- dsyslog("xmltv2vdr: ignoring non config file '%s'",dirent->d_name);
- }
- close(fd);
- }
- }
- else
- {
- esyslog("xmltv2vdr: cannot open config file '%s'",dirent->d_name);
- }
- }
- else
- {
- esyslog("xmltv2vdr: cannot access config file '%s'",dirent->d_name);
- }
- free(path);
- }
+ import->PutEvent(sources->GetSource(EITSOURCE),NULL,schedule,
+ (cEvent *) event,xevent,Flags,IMPORT_DESCRIPTION);
}
+ delete xevent;
}
- closedir(dir);
+ delete schedulesLock;
+ cSchedules::Cleanup(true);
}
-void cPluginXmltv2vdr::SetExecTime(int ExecTime)
-{
- exectime=ExecTime;
- exectime_t=cTimer::SetTime(time(NULL),cTimer::TimeToInt(exectime));
- if (exectime_t<=time(NULL)) exectime_t+=86000;
-}
+// -------------------------------------------------------------
cPluginXmltv2vdr::cPluginXmltv2vdr(void) : epgexecutor(&epgsources)
{
@@ -848,14 +202,17 @@ cPluginXmltv2vdr::cPluginXmltv2vdr(void) : epgexecutor(&epgsources)
// DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL
// VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT!
confdir=NULL;
- WakeUp=0;
- UpStart=1;
- last_exectime_t=0;
- exectime=200;
+ epgfile=NULL;
+ srcorder=NULL;
+ epghandler=NULL;
+ epgtimer=NULL;
+ last_housetime_t=0;
+ last_maintime_t=0;
+ last_epcheck_t=0;
+ wakeup=0;
SetEPAll(false);
- SetExecTime(exectime);
TEXTMappingAdd(new cTEXTMapping("country",tr("country")));
- TEXTMappingAdd(new cTEXTMapping("date",tr("year")));
+ TEXTMappingAdd(new cTEXTMapping("year",tr("year")));
TEXTMappingAdd(new cTEXTMapping("originaltitle",tr("originaltitle")));
TEXTMappingAdd(new cTEXTMapping("category",tr("category")));
TEXTMappingAdd(new cTEXTMapping("actor",tr("actor")));
@@ -868,7 +225,14 @@ cPluginXmltv2vdr::cPluginXmltv2vdr(void) : epgexecutor(&epgsources)
TEXTMappingAdd(new cTEXTMapping("presenter",tr("presenter")));
TEXTMappingAdd(new cTEXTMapping("producer",tr("producer")));
TEXTMappingAdd(new cTEXTMapping("writer",tr("writer")));
+ TEXTMappingAdd(new cTEXTMapping("video",tr("video")));
+ TEXTMappingAdd(new cTEXTMapping("blacknwhite",tr("blacknwhite")));
+ TEXTMappingAdd(new cTEXTMapping("audio",tr("audio")));
+ TEXTMappingAdd(new cTEXTMapping("dolby",tr("dolby")));
+ TEXTMappingAdd(new cTEXTMapping("dolbydigital",tr("dolbydigital")));
+ TEXTMappingAdd(new cTEXTMapping("bilingual",tr("bilingual")));
TEXTMappingAdd(new cTEXTMapping("review",tr("review")));
+ TEXTMappingAdd(new cTEXTMapping("starrating",tr("starrating")));
TEXTMappingAdd(new cTEXTMapping("season",tr("season")));
TEXTMappingAdd(new cTEXTMapping("episode",tr("episode")));
}
@@ -876,17 +240,72 @@ cPluginXmltv2vdr::cPluginXmltv2vdr(void) : epgexecutor(&epgsources)
cPluginXmltv2vdr::~cPluginXmltv2vdr()
{
// Clean up after yourself!
+#if VDRVERSNUM < 10726 && (!EPGHANDLER)
+ delete epghandler;
+#endif
}
+bool cPluginXmltv2vdr::EPGSourceMove(int From, int To)
+{
+ if (From==To) return false;
+ sqlite3 *db=NULL;
+ char *sql=NULL;
+ if (sqlite3_open_v2(epgfile,&db,SQLITE_OPEN_READWRITE,NULL)==SQLITE_OK)
+ {
+ if (asprintf(&sql,"BEGIN TRANSACTION;" \
+ "UPDATE epg SET srcidx=98 WHERE srcidx=%i;" \
+ "UPDATE epg SET srcidx=%i WHERE srcidx=%i;" \
+ "UPDATE epg SET srcidx=%i WHERE srcidx=98;" \
+ "COMMIT;", To, From, To, From)==-1)
+ {
+ sqlite3_close(db);
+ return false;
+ }
+ if (sqlite3_exec(db,sql,NULL,NULL,NULL)!=SQLITE_OK)
+ {
+ free(sql);
+ sqlite3_close(db);
+ return false;
+ }
+ }
+ free(sql);
+ sqlite3_close(db);
+ epgsources.Move(From,To);
+ return true;
+}
+
+
const char *cPluginXmltv2vdr::CommandLineHelp(void)
{
// Return a string that describes all known command line options.
- return NULL;
+ return " -E FILE, --epgfile=FILE write the EPG data into the given FILE(default is\n"
+ " 'epg.db' in the video directory)\n";
}
-bool cPluginXmltv2vdr::ProcessArgs(int UNUSED(argc), char *UNUSED(argv[]))
+bool cPluginXmltv2vdr::ProcessArgs(int argc, char *argv[])
{
- // Implement command line argument processing here if applicable.
+ // Command line argument processing
+ static struct option long_options[] =
+ {
+ { "epgfile", required_argument, NULL, 'E'
+ },
+ { 0,0,0,0 }
+ };
+
+ int c;
+ while ((c = getopt_long(argc, argv, "E:", long_options, NULL)) != -1)
+ {
+ switch (c)
+ {
+ case 'E':
+ if (epgfile) free(epgfile);
+ epgfile=strdup(optarg);
+ isyslog("xmltv2vdr: using file '%s' for epgdata",optarg);
+ break;
+ default:
+ return false;
+ }
+ }
return true;
}
@@ -900,45 +319,84 @@ bool cPluginXmltv2vdr::Start(void)
{
// Start any background activities the plugin shall perform.
confdir=strdup(ConfigDirectory(PLUGIN_NAME_I18N)); // creates internally the confdir!
- cParse::InitLibXML();
- ReadInEPGSources();
- if (UpStart)
+ if (!epgfile)
{
- exectime_t=time(NULL)+60;
- struct tm tm;
- localtime_r(&exectime_t,&tm);
- // prevent from getting startet again
- exectime=tm.tm_hour*100+tm.tm_min;
- }
- else
- {
- if (!exectime_t)
- {
- exectime_t=time(NULL)-60;
- last_exectime_t=exectime_t;
- }
+ if (asprintf(&epgfile,"%s/epg.db",VideoDirectory)==-1)return false;
}
+ cParse::InitLibXML();
+
+ ReadInEPGSources();
+ epghandler = new cEPGHandler(epgfile,&epgsources,&epgmappings,&textmappings);
+ epgtimer = new cEPGTimer(epgfile,&epgsources,&epgmappings,&textmappings);
+
+ if (sqlite3_threadsafe()==0) esyslog("xmltv2vdr: ERROR sqlite3 not threadsafe!");
return true;
}
void cPluginXmltv2vdr::Stop(void)
{
// Stop any background activities the plugin is performing.
+ cSchedules::Cleanup(true);
+ epgtimer->Stop();
+ delete epgtimer;
epgexecutor.Stop();
- removeepgsources();
- removeepgmappings();
- removetextmappings();
+ epgsources.Remove();
+ epgmappings.Remove();
+ textmappings.Remove();
cParse::CleanupLibXML();
if (confdir)
{
free(confdir);
confdir=NULL;
}
+ if (epgfile)
+ {
+ free(epgfile);
+ epgfile=NULL;
+ }
+ if (srcorder)
+ {
+ free(srcorder);
+ srcorder=NULL;
+ }
}
void cPluginXmltv2vdr::Housekeeping(void)
{
// Perform any cleanup or other regular tasks.
+ time_t now=time(NULL);
+ if (now>(last_housetime_t+3600))
+ {
+ struct stat statbuf;
+ if (stat(epgfile,&statbuf)!=-1)
+ {
+ if (statbuf.st_size)
+ {
+ sqlite3 *db=NULL;
+ if (sqlite3_open_v2(epgfile,&db,SQLITE_OPEN_READWRITE,NULL)==SQLITE_OK)
+ {
+ char *sql;
+ if (asprintf(&sql,"delete from epg where ((starttime+duration) < %li)",now)!=-1)
+ {
+ char *errmsg;
+ if (sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)
+ {
+ esyslog("xmltv2vdr: %s",errmsg);
+ sqlite3_free(errmsg);
+ }
+ else
+ {
+ isyslog("xmltv2vdr: removed %i old entries from db",sqlite3_changes(db));
+ sqlite3_exec(db,"VACCUM;",NULL,NULL,NULL);
+ }
+ free(sql);
+ }
+ }
+ sqlite3_close(db);
+ }
+ }
+ last_housetime_t=now;
+ }
}
void cPluginXmltv2vdr::MainThreadHook(void)
@@ -946,12 +404,24 @@ void cPluginXmltv2vdr::MainThreadHook(void)
// Perform actions in the context of the main program thread.
// WARNING: Use with great care - see PLUGINS.html!
time_t now=time(NULL);
- if (((now>=exectime_t) && (now<(exectime_t+10))) &&
- (last_exectime_t!=exectime_t))
+ if (now>(last_maintime_t+60))
{
- epgexecutor.Start();
- last_exectime_t=exectime_t;
- SetExecTime(exectime);
+ if (!epgexecutor.Active() && (!epgtimer->Active()))
+ {
+ if (epgsources.RunItNow()) epgexecutor.Start();
+ }
+ last_maintime_t=now;
+ }
+ if (epall)
+ {
+ if (now>(last_epcheck_t+600))
+ {
+ if (!epgtimer->Active() && (!epgexecutor.Active()))
+ {
+ epgtimer->Start();
+ }
+ last_epcheck_t=now;
+ }
}
}
@@ -968,19 +438,11 @@ cString cPluginXmltv2vdr::Active(void)
time_t cPluginXmltv2vdr::WakeupTime(void)
{
// Return custom wakeup time for shutdown script
- if (WakeUp)
- {
- time_t Now=time(NULL);
- time_t Time=cTimer::SetTime(Now,cTimer::TimeToInt(exectime));
- Time-=180;
- if (Time<=Now)
- Time=cTimer::IncDay(Time,1);
- return Time;
- }
- else
- {
- return 0;
- }
+ if (!wakeup) return (time_t) 0;
+
+ time_t nt=epgsources.NextRunTime();
+ if (nt) nt-=(time_t) 180;
+ return nt;
}
const char *cPluginXmltv2vdr::MainMenuEntry(void)
@@ -1007,9 +469,7 @@ bool cPluginXmltv2vdr::SetupParse(const char *Name, const char *Value)
if (!strncasecmp(Name,"channel",7))
{
if (strlen(Name)<10) return false;
-
- cEPGMapping *map = new cEPGMapping(&Name[8],Value);
- epgmappings.Add(map);
+ epgmappings.Add(new cEPGMapping(&Name[8],Value));
}
else if (!strncasecmp(Name,"textmap",7))
{
@@ -1021,25 +481,20 @@ bool cPluginXmltv2vdr::SetupParse(const char *Name, const char *Value)
}
else
{
- cTEXTMapping *textmap = new cTEXTMapping(&Name[8],Value);
- textmappings.Add(textmap);
+ textmappings.Add(new cTEXTMapping(&Name[8],Value));
}
}
- else if (!strcasecmp(Name,"options.exectime"))
+ else if (!strcasecmp(Name,"options.epall"))
{
- SetExecTime(atoi(Value));
+ SetEPAll((bool) atoi(Value));
}
else if (!strcasecmp(Name,"options.wakeup"))
{
- WakeUp=atoi(Value);
+ wakeup=(bool) atoi(Value);
}
- else if (!strcasecmp(Name,"options.upstart"))
+ else if (!strcasecmp(Name,"source.order"))
{
- UpStart=atoi(Value);
- }
- else if (!strcasecmp(Name,"options.epall"))
- {
- SetEPAll((bool) atoi(Value));
+ srcorder=strdup(Value);
}
else return false;
return true;