nathan@0: /* nathan@0: * PremiereEpg plugin to VDR (C++) nathan@0: * nathan@10: * (C) 2005-2006 Stefan Huelswitt nathan@0: * nathan@0: * This code is base on the commandline tool premiereepg2vdr nathan@0: * (C) 2004-2005 by Axel Katzur software@katzur.de nathan@0: * but has been rewritten from scratch nathan@0: * nathan@0: * This code is free software; you can redistribute it and/or nathan@0: * modify it under the terms of the GNU General Public License nathan@0: * as published by the Free Software Foundation; either version 2 nathan@0: * of the License, or (at your option) any later version. nathan@0: * nathan@0: * This code is distributed in the hope that it will be useful, nathan@0: * but WITHOUT ANY WARRANTY; without even the implied warranty of nathan@0: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nathan@0: * GNU General Public License for more details. nathan@0: * nathan@0: * You should have received a copy of the GNU General Public License nathan@0: * along with this program; if not, write to the Free Software nathan@0: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. nathan@0: * Or, point your browser to http://www.gnu.org/copyleft/gpl.html nathan@0: */ nathan@0: nathan@0: #include nathan@0: #include nathan@0: #include nathan@0: #include nathan@0: #include nathan@2: #include nathan@10: #include nathan@0: #include nathan@0: #include nathan@0: nathan@0: //#define DEBUG nathan@0: //#define DEBUG2 nathan@0: nathan@0: #ifdef DEBUG nathan@0: #define d(x) { (x); } nathan@0: #else nathan@0: #define d(x) ; nathan@0: #endif nathan@0: #ifdef DEBUG2 nathan@0: #define d2(x) { (x); } nathan@0: #else nathan@0: #define d2(x) ; nathan@0: #endif nathan@0: nathan@0: #define PMT_SCAN_TIMEOUT 10 // seconds nathan@0: #define PMT_SCAN_IDLE 300 // seconds nathan@0: nathan@10: static const char *VERSION = "0.0.6"; nathan@2: static const char *DESCRIPTION = "Parses extended Premiere EPG data"; nathan@2: nathan@10: #if APIVERSNUM < 10401 nathan@10: #error You need at least VDR API version 1.4.1 for this plugin nathan@10: #endif nathan@10: nathan@2: // --- cSetupPremiereEpg ------------------------------------------------------- nathan@2: nathan@2: const char *optPats[] = { nathan@2: "%s", nathan@2: "%s (Option %d)", nathan@2: "%s (O%d)", nathan@2: "#%2$d %1$s", nathan@2: "[%2$d] %1$s" nathan@2: }; nathan@2: #define NUM_PATS (sizeof(optPats)/sizeof(char *)) nathan@2: nathan@2: class cSetupPremiereEpg { nathan@2: public: nathan@2: int OptPat; nathan@6: int OrderInfo; nathan@6: int RatingInfo; nathan@2: public: nathan@2: cSetupPremiereEpg(void); nathan@2: }; nathan@2: nathan@2: cSetupPremiereEpg SetupPE; nathan@2: nathan@2: cSetupPremiereEpg::cSetupPremiereEpg(void) nathan@2: { nathan@2: OptPat=1; nathan@6: OrderInfo=1; nathan@6: RatingInfo=1; nathan@2: } nathan@2: nathan@2: // --- i18n -------------------------------------------------------------------- nathan@2: nathan@2: const tI18nPhrase Phrases[] = { nathan@2: /* nathan@2: */ nathan@2: { "PremiereEPG", nathan@2: "PremiereEPG", nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: }, nathan@2: { "Parses extended Premiere EPG data", nathan@2: "Liest erweiterte Premiere EPG Daten ein", nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: }, nathan@2: { "Tag option events", nathan@2: "Options Events markieren", nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: "", // TODO nathan@2: }, nathan@6: { "Show order information", nathan@6: "Bestellhinweise anzeigen", nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: }, nathan@6: { "Show rating information", nathan@6: "Altersfreigaben anzeigen", nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: }, nathan@6: nathan@6: { "Ordernumber", nathan@6: "Bestellnummer", nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: }, nathan@6: { "Price", nathan@6: "Preis", nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: }, nathan@6: { "Ordering", nathan@6: "Bestellen", nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: }, nathan@6: { "SMS", nathan@6: "SMS", nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: }, nathan@6: { "WWW", nathan@6: "WWW", nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: }, nathan@6: { "Rating", nathan@6: "Altersfreigabe", nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: }, nathan@6: { "years", nathan@6: "Jahre", nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: "", // TODO nathan@6: }, nathan@2: nathan@2: { NULL } nathan@2: }; nathan@2: nathan@2: // --- cMenuSetupPremiereEpg ------------------------------------------------------------ nathan@2: nathan@2: class cMenuSetupPremiereEpg : public cMenuSetupPage { nathan@2: private: nathan@2: cSetupPremiereEpg data; nathan@2: const char *optDisp[NUM_PATS]; nathan@2: char buff[NUM_PATS][32]; nathan@2: protected: nathan@2: virtual void Store(void); nathan@2: public: nathan@2: cMenuSetupPremiereEpg(void); nathan@2: }; nathan@2: nathan@2: cMenuSetupPremiereEpg::cMenuSetupPremiereEpg(void) nathan@2: { nathan@2: data=SetupPE; nathan@2: SetSection(tr("PremiereEPG")); nathan@2: optDisp[0]=tr("off"); nathan@2: for(unsigned int i=1; i>1)^POLY : (crc>>1); nathan@0: } nathan@10: return crc&0xFFFF; nathan@0: } nathan@0: nathan@0: // --- cFilterPremiereEpg ------------------------------------------------------ nathan@0: nathan@10: #define STARTTIME_BIAS (20*60) nathan@10: nathan@0: class cFilterPremiereEpg : public cFilter { nathan@0: private: nathan@10: int pmtpid, pmtsid, pmtidx, pmtnext; nathan@0: // nathan@0: void NextPmt(void); nathan@0: protected: nathan@0: virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length); nathan@0: public: nathan@0: cFilterPremiereEpg(void); nathan@0: virtual void SetStatus(bool On); nathan@0: void Trigger(void); nathan@0: }; nathan@0: nathan@0: cFilterPremiereEpg::cFilterPremiereEpg(void) nathan@0: { nathan@0: Trigger(); nathan@0: Set(0x00,0x00); nathan@0: } nathan@0: nathan@0: void cFilterPremiereEpg::Trigger(void) nathan@0: { nathan@0: d(printf("trigger\n")) nathan@0: pmtpid=0; pmtidx=0; pmtnext=0; nathan@0: } nathan@0: nathan@0: void cFilterPremiereEpg::SetStatus(bool On) nathan@0: { nathan@0: d(printf("setstatus %d\n",On)) nathan@0: cFilter::SetStatus(On); nathan@0: Trigger(); nathan@0: } nathan@0: nathan@0: void cFilterPremiereEpg::NextPmt(void) nathan@0: { nathan@0: Del(pmtpid,0x02); nathan@0: pmtpid=0; nathan@0: pmtidx++; nathan@0: d(printf("PMT next\n")) nathan@0: } nathan@0: nathan@0: void cFilterPremiereEpg::Process(u_short Pid, u_char Tid, const u_char *Data, int Length) nathan@0: { nathan@10: int now=time(0); nathan@0: if(Pid==0 && Tid==SI::TableIdPAT) { nathan@0: if(!pmtnext || now>pmtnext) { nathan@0: if(pmtpid) NextPmt(); nathan@0: if(!pmtpid) { nathan@0: SI::PAT pat(Data,false); nathan@0: if(pat.CheckCRCAndParse()) { nathan@0: SI::PAT::Association assoc; nathan@0: int idx=0; nathan@0: for(SI::Loop::Iterator it; pat.associationLoop.getNext(assoc,it);) { nathan@0: if(!assoc.isNITPid()) { nathan@0: if(idx++==pmtidx) { nathan@0: pmtpid=assoc.getPid(); nathan@10: pmtsid=assoc.getServiceId(); nathan@0: Add(pmtpid,0x02); nathan@0: pmtnext=now+PMT_SCAN_TIMEOUT; nathan@0: d(printf("PMT pid now 0x%04x (idx=%d)\n",pmtpid,pmtidx)) nathan@0: break; nathan@0: } nathan@0: } nathan@0: } nathan@0: if(!pmtpid) { nathan@0: pmtidx=0; nathan@0: pmtnext=now+PMT_SCAN_IDLE; nathan@0: d(printf("PMT scan idle\n")) nathan@0: } nathan@0: } nathan@0: } nathan@0: } nathan@0: } nathan@0: else if(pmtpid>0 && Pid==pmtpid && Tid==SI::TableIdPMT && Source() && Transponder()) { nathan@0: SI::PMT pmt(Data,false); nathan@10: if(pmt.CheckCRCAndParse() && pmt.getServiceId()==pmtsid) { nathan@0: SI::PMT::Stream stream; nathan@0: for(SI::Loop::Iterator it; pmt.streamLoop.getNext(stream,it); ) { nathan@0: if(stream.getStreamType()==0x05) { nathan@0: SI::CharArray data=stream.getData(); nathan@0: if((data[1]&0xE0)==0xE0 && (data[3]&0xF0)==0xF0) { nathan@0: bool prvData=false, usrData=false; nathan@0: SI::Descriptor *d; nathan@0: for(SI::Loop::Iterator it; (d=stream.streamDescriptors.getNext(it)); ) { nathan@0: switch(d->getDescriptorTag()) { nathan@0: case SI::PrivateDataSpecifierDescriptorTag: nathan@0: d(printf("prv: %d %08x\n",d->getLength(),d->getData().FourBytes(2))) nathan@0: if(d->getLength()==6 && d->getData().FourBytes(2)==0x000000be) nathan@0: prvData=true; nathan@0: break; nathan@0: case 0x90: nathan@0: d(printf("usr: %d %08x\n",d->getLength(),d->getData().FourBytes(2))) nathan@0: if(d->getLength()==6 && d->getData().FourBytes(2)==0x0000ffff) nathan@0: usrData=true; nathan@0: break; nathan@0: default: nathan@0: break; nathan@0: } nathan@0: delete d; nathan@0: } nathan@0: if(prvData && usrData) { nathan@0: int pid=stream.getPid(); nathan@0: d(printf("found citpid 0x%04x",pid)) nathan@0: if(!Matches(pid,0xA0)) { nathan@0: Add(pid,0xA0); nathan@0: d(printf(" (added)")) nathan@0: } nathan@0: d(printf("\n")) nathan@0: } nathan@0: } nathan@0: } nathan@0: } nathan@0: NextPmt(); pmtnext=0; nathan@0: } nathan@0: } nathan@0: else if(Tid==0xA0 && Source()) { nathan@10: SI::PremiereCIT cit(Data,false); nathan@0: if(cit.CheckCRCAndParse()) { nathan@0: cSchedulesLock SchedulesLock(true,10); nathan@0: cSchedules *Schedules=(cSchedules *)cSchedules::Schedules(SchedulesLock); nathan@0: if(Schedules) { nathan@0: int nCount=0; nathan@0: SI::ExtendedEventDescriptors *ExtendedEventDescriptors=0; nathan@0: SI::ShortEventDescriptor *ShortEventDescriptor=0; nathan@6: char *order=0, *rating=0; nathan@10: { nathan@10: time_t firstTime=0; nathan@10: SI::Descriptor *d; nathan@10: bool UseExtendedEventDescriptor=false; nathan@10: int LanguagePreferenceShort=-1; nathan@10: int LanguagePreferenceExt=-1; nathan@0: for(SI::Loop::Iterator it; (d=cit.eventDescriptors.getNext(it)); ) { nathan@0: switch(d->getDescriptorTag()) { nathan@6: case 0xF0: // order information nathan@6: if(SetupPE.OrderInfo) { nathan@6: static const char *text[] = { nathan@6: "Ordernumber", nathan@6: "Price", nathan@6: "Ordering", nathan@6: "SMS", nathan@6: "WWW" nathan@6: }; nathan@6: char buff[512]; nathan@6: int p=0; nathan@6: const unsigned char *data=d->getData().getData()+2; nathan@6: for(int i=0; i<5; i++) { nathan@6: int l=data[0]; nathan@6: if(l>0) p+=snprintf(&buff[p],sizeof(buff)-p,"\n%s: %.*s",tr(text[i]),l,&data[1]); nathan@6: data+=l+1; nathan@6: } nathan@6: if(p>0) order=strdup(buff); nathan@6: } nathan@6: break; nathan@6: case 0xF1: // parental rating nathan@6: if(SetupPE.RatingInfo) { nathan@6: char buff[512]; nathan@6: int p=0; nathan@6: const unsigned char *data=d->getData().getData()+2; nathan@6: p+=snprintf(&buff[p],sizeof(buff)-p,"\n%s: %d %s",tr("Rating"),data[0]+3,tr("years")); nathan@6: data+=7; nathan@6: int l=data[0]; nathan@6: if(l>0) p+=snprintf(&buff[p],sizeof(buff)-p," (%.*s)",l,&data[1]); nathan@6: if(p>0) rating=strdup(buff); nathan@6: } nathan@6: break; nathan@10: case SI::PremiereContentTransmissionDescriptorTag: nathan@0: if(nCount>=0) { nathan@10: SI::PremiereContentTransmissionDescriptor *pct=(SI::PremiereContentTransmissionDescriptor *)d; nathan@0: nCount++; nathan@10: SI::PremiereContentTransmissionDescriptor::StartDayEntry sd; nathan@10: SI::Loop::Iterator it; nathan@10: if(pct->startDayLoop.getNext(sd,it)) { nathan@10: SI::PremiereContentTransmissionDescriptor::StartDayEntry::StartTimeEntry st; nathan@10: SI::Loop::Iterator it2; nathan@10: if(sd.startTimeLoop.getNext(st,it2)) { nathan@10: time_t StartTime=st.getStartTime(sd.getMJD()); nathan@10: if(nCount==1) firstTime=StartTime; nathan@10: else if(firstTimeStartTime+5*60) nathan@0: nCount=-1; nathan@0: } nathan@0: } nathan@0: } nathan@0: break; nathan@0: case SI::ExtendedEventDescriptorTag: nathan@0: { nathan@0: SI::ExtendedEventDescriptor *eed=(SI::ExtendedEventDescriptor *)d; nathan@4: if(I18nIsPreferredLanguage(Setup.EPGLanguages,eed->languageCode, LanguagePreferenceExt) || !ExtendedEventDescriptors) { nathan@0: delete ExtendedEventDescriptors; nathan@0: ExtendedEventDescriptors=new SI::ExtendedEventDescriptors; nathan@0: UseExtendedEventDescriptor=true; nathan@0: } nathan@0: if(UseExtendedEventDescriptor) { nathan@0: ExtendedEventDescriptors->Add(eed); nathan@0: d=NULL; // so that it is not deleted nathan@0: } nathan@0: if(eed->getDescriptorNumber()==eed->getLastDescriptorNumber()) nathan@0: UseExtendedEventDescriptor=false; nathan@0: } nathan@0: break; nathan@0: case SI::ShortEventDescriptorTag: nathan@0: { nathan@0: SI::ShortEventDescriptor *sed=(SI::ShortEventDescriptor *)d; nathan@4: if(I18nIsPreferredLanguage(Setup.EPGLanguages,sed->languageCode, LanguagePreferenceShort) || !ShortEventDescriptor) { nathan@0: delete ShortEventDescriptor; nathan@0: ShortEventDescriptor=sed; nathan@0: d=NULL; // so that it is not deleted nathan@0: } nathan@0: } nathan@0: break; nathan@0: default: nathan@0: break; nathan@0: } nathan@0: delete d; nathan@0: } nathan@10: } nathan@10: nathan@10: { nathan@0: bool Modified=false; nathan@0: int optCount=0; nathan@10: unsigned int crc[3]; nathan@10: crc[0]=cit.getContentId(); nathan@10: SI::PremiereContentTransmissionDescriptor *pct; nathan@10: for(SI::Loop::Iterator it; (pct=(SI::PremiereContentTransmissionDescriptor *)cit.eventDescriptors.getNext(it,SI::PremiereContentTransmissionDescriptorTag)); ) { nathan@10: tChannelID channelID(Source(),pct->getOriginalNetworkId(),pct->getTransportStreamId(),pct->getServiceId()); nathan@10: cChannel *channel=Channels.GetByChannelID(channelID,true); nathan@10: if(!channel) continue; nathan@10: nathan@10: cSchedule *pSchedule=(cSchedule *)Schedules->GetSchedule(channelID); nathan@10: if(!pSchedule) { nathan@10: pSchedule=new cSchedule(channelID); nathan@10: Schedules->Add(pSchedule); nathan@10: } nathan@10: nathan@10: optCount++; nathan@10: SI::PremiereContentTransmissionDescriptor::StartDayEntry sd; nathan@10: int index=0; nathan@10: for(SI::Loop::Iterator it; pct->startDayLoop.getNext(sd,it); ) { nathan@10: int mjd=sd.getMJD(); nathan@10: SI::PremiereContentTransmissionDescriptor::StartDayEntry::StartTimeEntry st; nathan@10: for(SI::Loop::Iterator it2; sd.startTimeLoop.getNext(st,it2); ) { nathan@10: time_t StartTime=st.getStartTime(mjd); nathan@10: time_t EndTime=StartTime+cit.getDuration(); nathan@10: int runningStatus=(StartTime1) isOpt=true; nathan@10: crc[1]=isOpt ? optCount : 0; nathan@10: crc[2]=StartTime / STARTTIME_BIAS; nathan@10: tEventID EventId=((('P'<<8)|'W')<<16) | crc16(0,(unsigned char *)crc,sizeof(crc)); nathan@10: nathan@10: d2(printf("%s R%d %04x/%.4x %d %d/%d %s +%d ",*channelID.ToString(),runningStatus,EventId&0xFFFF,cit.getContentId(),index,isOpt,optCount,stripspace(ctime(&StartTime)),(int)cit.getDuration()/60)) nathan@10: if(EndTime+Setup.EPGLinger*60GetEvent(EventId,-1); nathan@0: if(!pEvent) { nathan@10: d2(printf("(new)\n")) nathan@10: pEvent=new cEvent(EventId); nathan@10: if(!pEvent) continue; nathan@10: newEvent=true; nathan@10: } nathan@0: else { nathan@10: d2(printf("(upd)\n")) nathan@10: pEvent->SetSeen(); nathan@10: if(pEvent->TableID()==0x00 || pEvent->Version()==cit.getVersionNumber()) { nathan@10: if(pEvent->RunningStatus()!=runningStatus) nathan@10: pSchedule->SetRunningStatus(pEvent,runningStatus,channel); nathan@10: continue; nathan@10: } nathan@10: } nathan@0: pEvent->SetEventID(EventId); nathan@0: pEvent->SetTableID(Tid); nathan@0: pEvent->SetVersion(cit.getVersionNumber()); nathan@0: pEvent->SetStartTime(StartTime); nathan@0: pEvent->SetDuration(cit.getDuration()); nathan@0: nathan@0: if(ShortEventDescriptor) { nathan@2: char buffer[256]; nathan@2: ShortEventDescriptor->name.getText(buffer,sizeof(buffer)); nathan@0: if(isOpt) { nathan@2: char buffer2[sizeof(buffer)+32]; nathan@2: snprintf(buffer2,sizeof(buffer2),optPats[SetupPE.OptPat],buffer,optCount); nathan@2: pEvent->SetTitle(buffer2); nathan@0: } nathan@2: else nathan@2: pEvent->SetTitle(buffer); nathan@10: d2(printf("title: %s\n",pEvent->Title())) nathan@0: pEvent->SetShortText(ShortEventDescriptor->text.getText(buffer,sizeof(buffer))); nathan@0: } nathan@0: if(ExtendedEventDescriptors) { nathan@0: char buffer[ExtendedEventDescriptors->getMaximumTextLength(": ")+1]; nathan@0: pEvent->SetDescription(ExtendedEventDescriptors->getText(buffer,sizeof(buffer),": ")); nathan@0: } nathan@6: if(order || rating) { nathan@6: int len=(pEvent->Description() ? strlen(pEvent->Description()) : 0) + nathan@6: (order ? strlen(order) : 0) + nathan@6: (rating ? strlen(rating) : 0); nathan@6: char buffer[len+32]; nathan@6: buffer[0]=0; nathan@6: if(pEvent->Description()) strcat(buffer,pEvent->Description()); nathan@6: if(rating) strcat(buffer,rating); nathan@6: if(order) strcat(buffer,order); nathan@6: pEvent->SetDescription(buffer); nathan@6: } nathan@0: nathan@2: if(newEvent) pSchedule->AddEvent(pEvent); nathan@0: pEvent->SetComponents(NULL); nathan@0: pEvent->FixEpgBugs(); nathan@10: if(pEvent->RunningStatus()!=runningStatus) nathan@10: pSchedule->SetRunningStatus(pEvent,runningStatus,channel); nathan@10: pSchedule->DropOutdated(StartTime,EndTime,Tid,cit.getVersionNumber()); nathan@0: Modified=true; nathan@0: } nathan@0: } nathan@10: if(Modified) { nathan@10: pSchedule->Sort(); nathan@10: Schedules->SetModified(pSchedule); nathan@10: } nathan@10: delete pct; nathan@0: } nathan@10: } nathan@0: delete ExtendedEventDescriptors; nathan@0: delete ShortEventDescriptor; nathan@6: free(order); nathan@6: free(rating); nathan@0: } nathan@0: } nathan@0: } nathan@0: } nathan@0: nathan@0: // --- cPluginPremiereEpg ------------------------------------------------------ nathan@0: nathan@0: class cPluginPremiereEpg : public cPlugin { nathan@0: private: nathan@0: struct { nathan@0: cFilterPremiereEpg *filter; nathan@0: cDevice *device; nathan@0: } epg[MAXDVBDEVICES]; nathan@0: public: nathan@0: cPluginPremiereEpg(void); nathan@0: virtual const char *Version(void) { return VERSION; } nathan@2: virtual const char *Description(void) { return tr(DESCRIPTION); } nathan@0: virtual bool Start(void); nathan@0: virtual void Stop(void); nathan@2: virtual cMenuSetupPage *SetupMenu(void); nathan@2: virtual bool SetupParse(const char *Name, const char *Value); nathan@0: }; nathan@0: nathan@0: cPluginPremiereEpg::cPluginPremiereEpg(void) nathan@0: { nathan@0: memset(epg,0,sizeof(epg)); nathan@0: } nathan@0: nathan@0: bool cPluginPremiereEpg::Start(void) nathan@0: { nathan@2: RegisterI18n(Phrases); nathan@0: for(int i=0; iAttachFilter(epg[i].filter=new cFilterPremiereEpg); nathan@0: isyslog("Attached premiere EPG filter to device %d",i); nathan@0: } nathan@0: } nathan@0: return true; nathan@0: } nathan@0: nathan@0: void cPluginPremiereEpg::Stop(void) nathan@0: { nathan@0: for(int i=0; iDetach(epg[i].filter); nathan@0: delete epg[i].filter; nathan@0: epg[i].device=0; nathan@0: epg[i].filter=0; nathan@0: } nathan@0: } nathan@0: nathan@2: cMenuSetupPage *cPluginPremiereEpg::SetupMenu(void) nathan@2: { nathan@2: return new cMenuSetupPremiereEpg; nathan@2: } nathan@2: nathan@2: bool cPluginPremiereEpg::SetupParse(const char *Name, const char *Value) nathan@2: { nathan@6: if (!strcasecmp(Name, "OptionPattern")) SetupPE.OptPat = atoi(Value); nathan@6: else if (!strcasecmp(Name, "OrderInfo")) SetupPE.OrderInfo = atoi(Value); nathan@6: else if (!strcasecmp(Name, "RatingInfo")) SetupPE.RatingInfo = atoi(Value); nathan@2: else return false; nathan@2: return true; nathan@2: } nathan@2: nathan@0: VDRPLUGINCREATOR(cPluginPremiereEpg); // Don't touch this!