premiereepg.c
author nathan
Sun, 22 Feb 2009 21:02:54 +0800
branchtrunk
changeset 29 a0f32201f466
parent 26 0953c008ab80
permissions -rw-r--r--
add italian translations
     1 /*
     2  * PremiereEpg plugin to VDR (C++)
     3  *
     4  * (C) 2005-2008 Stefan Huelswitt <s.huelswitt@gmx.de>
     5  *
     6  * This code is base on the commandline tool premiereepg2vdr
     7  * (C) 2004-2005 by Axel Katzur software@katzur.de
     8  * but has been rewritten from scratch
     9  *
    10  * This code is free software; you can redistribute it and/or
    11  * modify it under the terms of the GNU General Public License
    12  * as published by the Free Software Foundation; either version 2
    13  * of the License, or (at your option) any later version.
    14  *
    15  * This code is distributed in the hope that it will be useful,
    16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    18  * GNU General Public License for more details.
    19  *
    20  * You should have received a copy of the GNU General Public License
    21  * along with this program; if not, write to the Free Software
    22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
    23  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
    24  */
    25 
    26 #include <stdarg.h>
    27 #include <vdr/plugin.h>
    28 #include <vdr/filter.h>
    29 #include <vdr/epg.h>
    30 #include <vdr/channels.h>
    31 #include <vdr/dvbdevice.h>
    32 #include <vdr/i18n.h>
    33 #include <vdr/config.h>
    34 #include <libsi/section.h>
    35 #include <libsi/descriptor.h>
    36 #include "i18n.h"
    37 #include "version.h"
    38 
    39 #if APIVERSNUM < 10401
    40 #error You need at least VDR API version 1.4.1 for this plugin
    41 #endif
    42 
    43 //#define DEBUG
    44 //#define DEBUG2
    45 
    46 #ifdef DEBUG
    47 #define d(x) { (x); }
    48 #else
    49 #define d(x) ; 
    50 #endif
    51 #ifdef DEBUG2
    52 #define d2(x) { (x); }
    53 #else
    54 #define d2(x) ; 
    55 #endif
    56 
    57 #define PMT_SCAN_TIMEOUT  10  // seconds
    58 #define PMT_SCAN_IDLE     300 // seconds
    59 
    60 // --- cSetupPremiereEpg -------------------------------------------------------
    61 
    62 const char *optPats[] = {
    63   "%s",
    64   "%s (Option %d)",
    65   "%s (O%d)",
    66   "#%2$d %1$s",
    67   "[%2$d] %1$s"
    68   };
    69 #define NUM_PATS (sizeof(optPats)/sizeof(char *))
    70 
    71 class cSetupPremiereEpg {
    72 public:
    73   int OptPat;
    74   int OrderInfo;
    75   int RatingInfo;
    76   int FixEpg;
    77 public:
    78   cSetupPremiereEpg(void);
    79   };
    80 
    81 cSetupPremiereEpg SetupPE;
    82 
    83 cSetupPremiereEpg::cSetupPremiereEpg(void)
    84 {
    85   OptPat=1;
    86   OrderInfo=1;
    87   RatingInfo=1;
    88   FixEpg=0;
    89 }
    90 
    91 // --- cMenuSetupPremiereEpg ------------------------------------------------------------
    92 
    93 class cMenuSetupPremiereEpg : public cMenuSetupPage {
    94 private:
    95   cSetupPremiereEpg data;
    96   const char *optDisp[NUM_PATS];
    97   char buff[NUM_PATS][32];
    98 protected:
    99   virtual void Store(void);
   100 public:
   101   cMenuSetupPremiereEpg(void);
   102   };
   103 
   104 cMenuSetupPremiereEpg::cMenuSetupPremiereEpg(void)
   105 {
   106   data=SetupPE;
   107   SetSection(tr("PremiereEPG"));
   108   optDisp[0]=tr("off");
   109   for(unsigned int i=1; i<NUM_PATS; i++) {
   110     snprintf(buff[i],sizeof(buff[i]),optPats[i],"Event",1);
   111     optDisp[i]=buff[i];
   112     }
   113   Add(new cMenuEditStraItem(tr("Tag option events"),&data.OptPat,NUM_PATS,optDisp));
   114   Add(new cMenuEditBoolItem(tr("Show order information"),&data.OrderInfo));
   115   Add(new cMenuEditBoolItem(tr("Show rating information"),&data.RatingInfo));
   116   Add(new cMenuEditBoolItem(tr("Fix EPG data"),&data.FixEpg));
   117 }
   118 
   119 void cMenuSetupPremiereEpg::Store(void)
   120 {
   121   SetupPE=data;
   122   SetupStore("OptionPattern",SetupPE.OptPat);
   123   SetupStore("OrderInfo",SetupPE.OrderInfo);
   124   SetupStore("RatingInfo",SetupPE.RatingInfo);
   125   SetupStore("FixEpg",SetupPE.FixEpg);
   126 }
   127 
   128 // --- CRC16 -------------------------------------------------------------------
   129 
   130 #define POLY 0xA001 // CRC16
   131 
   132 unsigned int crc16(unsigned int crc, unsigned char const *p, int len)
   133 {
   134   while(len--) {
   135     crc^=*p++;
   136     for(int i=0; i<8; i++)
   137       crc=(crc&1) ? (crc>>1)^POLY : (crc>>1);
   138     }
   139   return crc&0xFFFF;
   140 }
   141 
   142 // --- cStrBuff ----------------------------------------------------------------
   143 
   144 class cStrBuff {
   145 private:
   146   char *buff;
   147   int size, pos;
   148 public:
   149   cStrBuff(int Size);
   150   ~cStrBuff();
   151   void Printf(const char *fmt, ...) __attribute__ ((format (printf,2,3)));
   152   char *Buff(void) { return (buff && pos>0) ? strdup(buff):0; }
   153   };
   154 
   155 cStrBuff::cStrBuff(int Size)
   156 {
   157   size=Size; pos=0;
   158   buff=MALLOC(char,size);
   159 }
   160 
   161 cStrBuff::~cStrBuff()
   162 {
   163   free(buff);
   164 }
   165 
   166 void cStrBuff::Printf(const char *fmt, ...)
   167 {
   168   int s=size-pos;
   169   if(buff && s>0) {
   170     va_list ap;
   171     va_start(ap,fmt);
   172     int q=vsnprintf(buff+pos,s,fmt,ap);
   173     va_end(ap);
   174     if(q>0) pos+=q;
   175     }
   176 }
   177 
   178 // --- cFilterPremiereEpg ------------------------------------------------------
   179 
   180 #define STARTTIME_BIAS (20*60)
   181 
   182 class cFilterPremiereEpg : public cFilter {
   183 private:
   184   int pmtpid, pmtsid, pmtidx, pmtnext;
   185   //
   186   void NextPmt(void);
   187 protected:
   188   virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length);
   189 public:
   190   cFilterPremiereEpg(void);
   191   virtual void SetStatus(bool On);
   192   void Trigger(void);
   193   };
   194 
   195 cFilterPremiereEpg::cFilterPremiereEpg(void)
   196 {
   197   Trigger();
   198   Set(0x00,0x00);
   199 }
   200 
   201 void cFilterPremiereEpg::Trigger(void)
   202 {
   203   d(printf("trigger\n"))
   204   pmtpid=0; pmtidx=0; pmtnext=0;
   205 }
   206 
   207 void cFilterPremiereEpg::SetStatus(bool On)
   208 {
   209   d(printf("setstatus %d\n",On))
   210   cFilter::SetStatus(On);
   211   Trigger();
   212 }
   213 
   214 void cFilterPremiereEpg::NextPmt(void)
   215 {
   216   Del(pmtpid,0x02);
   217   pmtpid=0;
   218   pmtidx++;
   219   d(printf("PMT next\n"))
   220 }
   221 
   222 void cFilterPremiereEpg::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
   223 {
   224   int now=time(0);
   225   if(Pid==0 && Tid==SI::TableIdPAT) {
   226     if(!pmtnext || now>pmtnext) {
   227       if(pmtpid) NextPmt();
   228       if(!pmtpid) {
   229         SI::PAT pat(Data,false);
   230         if(pat.CheckCRCAndParse()) {
   231           SI::PAT::Association assoc;
   232           int idx=0;
   233           for(SI::Loop::Iterator it; pat.associationLoop.getNext(assoc,it);) {
   234             if(!assoc.isNITPid()) {
   235               if(idx++==pmtidx) {
   236                 pmtpid=assoc.getPid();
   237                 pmtsid=assoc.getServiceId();
   238                 Add(pmtpid,0x02);
   239                 pmtnext=now+PMT_SCAN_TIMEOUT;
   240                 d(printf("PMT pid now 0x%04x (idx=%d)\n",pmtpid,pmtidx))
   241                 break;
   242                 }
   243               }
   244             }
   245           if(!pmtpid) {
   246             pmtidx=0;
   247             pmtnext=now+PMT_SCAN_IDLE;
   248             d(printf("PMT scan idle\n"))
   249             }
   250           }
   251         }
   252       }
   253     }
   254   else if(pmtpid>0 && Pid==pmtpid && Tid==SI::TableIdPMT && Source() && Transponder()) {
   255     SI::PMT pmt(Data,false);
   256     if(pmt.CheckCRCAndParse() && pmt.getServiceId()==pmtsid) {
   257       SI::PMT::Stream stream;
   258       for(SI::Loop::Iterator it; pmt.streamLoop.getNext(stream,it); ) {
   259         if(stream.getStreamType()==0x05) {
   260           SI::CharArray data=stream.getData();
   261           if((data[1]&0xE0)==0xE0 && (data[3]&0xF0)==0xF0) {
   262             bool prvData=false, usrData=false;
   263             SI::Descriptor *d;
   264             for(SI::Loop::Iterator it; (d=stream.streamDescriptors.getNext(it)); ) {
   265               switch(d->getDescriptorTag()) {
   266                 case SI::PrivateDataSpecifierDescriptorTag:
   267                   d(printf("prv: %d %08x\n",d->getLength(),d->getData().FourBytes(2)))
   268                   if(d->getLength()==6 && d->getData().FourBytes(2)==0x000000be)
   269                     prvData=true;
   270                   break;
   271                 case 0x90:
   272                   d(printf("usr: %d %08x\n",d->getLength(),d->getData().FourBytes(2)))
   273                   if(d->getLength()==6 && d->getData().FourBytes(2)==0x0000ffff)
   274                     usrData=true;
   275                   break;
   276                 default:
   277                   break;
   278                 }
   279               delete d;
   280               }
   281             if(prvData && usrData) {
   282               int pid=stream.getPid();
   283               d(printf("found citpid 0x%04x",pid))
   284               if(!Matches(pid,0xA0)) {
   285                 Add(pid,0xA0);
   286                 d(printf(" (added)"))
   287                 }
   288               d(printf("\n"))
   289               }
   290             }
   291           }
   292         }
   293       NextPmt(); pmtnext=0;
   294       }
   295     }
   296   else if(Tid==0xA0 && Source()) {
   297     SI::PremiereCIT cit(Data,false);
   298     if(cit.CheckCRCAndParse()) {
   299       cSchedulesLock SchedulesLock(true,10);
   300       cSchedules *Schedules=(cSchedules *)cSchedules::Schedules(SchedulesLock);
   301       if(Schedules) {
   302         int nCount=0;
   303         SI::ExtendedEventDescriptors *ExtendedEventDescriptors=0;
   304         SI::ShortEventDescriptor *ShortEventDescriptor=0;
   305         char *order=0, *rating=0;
   306         {
   307         time_t firstTime=0;
   308         SI::Descriptor *d;
   309         bool UseExtendedEventDescriptor=false;
   310         int LanguagePreferenceShort=-1;
   311         int LanguagePreferenceExt=-1;
   312         for(SI::Loop::Iterator it; (d=cit.eventDescriptors.getNext(it)); ) {
   313           switch(d->getDescriptorTag()) {
   314             case 0xF0: // order information
   315               if(SetupPE.OrderInfo) {
   316                 static const char *text[] = {
   317                   trNOOP("Ordernumber"),
   318                   trNOOP("Price"),
   319                   trNOOP("Ordering"),
   320                   trNOOP("SMS"),
   321                   trNOOP("WWW")
   322                   };
   323                 cStrBuff str(1024);
   324                 const unsigned char *data=d->getData().getData()+2;
   325                 for(int i=0; i<5; i++) {
   326                   int l=data[0]; 
   327                   if(l>0) str.Printf("\n%s: %.*s",tr(text[i]),l,&data[1]);
   328                   data+=l+1;
   329                   }
   330                 order=str.Buff();
   331                 }
   332               break;
   333             case 0xF1: // parental rating
   334               if(SetupPE.RatingInfo) {
   335                 cStrBuff str(1024);
   336                 const unsigned char *data=d->getData().getData()+2;
   337                 str.Printf("\n%s: %d %s",tr("Rating"),data[0]+3,tr("years"));
   338                 data+=7;
   339                 int l=data[0]; 
   340                 if(l>0) str.Printf(" (%.*s)",l,&data[1]);
   341                 rating=str.Buff();
   342                 }
   343               break;
   344             case SI::PremiereContentTransmissionDescriptorTag:
   345               if(nCount>=0) {
   346                 SI::PremiereContentTransmissionDescriptor *pct=(SI::PremiereContentTransmissionDescriptor *)d;
   347                 nCount++;
   348                 SI::PremiereContentTransmissionDescriptor::StartDayEntry sd;
   349                 SI::Loop::Iterator it;
   350                 if(pct->startDayLoop.getNext(sd,it)) {
   351                   SI::PremiereContentTransmissionDescriptor::StartDayEntry::StartTimeEntry st;
   352                   SI::Loop::Iterator it2;
   353                   if(sd.startTimeLoop.getNext(st,it2)) {
   354                     time_t StartTime=st.getStartTime(sd.getMJD());
   355                     if(nCount==1) firstTime=StartTime;
   356                     else if(firstTime<StartTime-5*50 || firstTime>StartTime+5*60)
   357                       nCount=-1;
   358                     }
   359                   }
   360                 }
   361               break;
   362             case SI::ExtendedEventDescriptorTag:
   363               {
   364               SI::ExtendedEventDescriptor *eed=(SI::ExtendedEventDescriptor *)d;
   365               if(I18nIsPreferredLanguage(Setup.EPGLanguages,eed->languageCode, LanguagePreferenceExt) || !ExtendedEventDescriptors) {
   366                  delete ExtendedEventDescriptors;
   367                  ExtendedEventDescriptors=new SI::ExtendedEventDescriptors;
   368                  UseExtendedEventDescriptor=true;
   369                  }
   370               if(UseExtendedEventDescriptor) {
   371                  ExtendedEventDescriptors->Add(eed);
   372                  d=NULL; // so that it is not deleted
   373                  }
   374               if(eed->getDescriptorNumber()==eed->getLastDescriptorNumber())
   375                  UseExtendedEventDescriptor=false;
   376               }
   377               break;
   378             case SI::ShortEventDescriptorTag:
   379               {
   380               SI::ShortEventDescriptor *sed=(SI::ShortEventDescriptor *)d;
   381               if(I18nIsPreferredLanguage(Setup.EPGLanguages,sed->languageCode, LanguagePreferenceShort) || !ShortEventDescriptor) {
   382                  delete ShortEventDescriptor;
   383                  ShortEventDescriptor=sed;
   384                  d=NULL; // so that it is not deleted
   385                  }
   386               }
   387               break;
   388             default:
   389               break;
   390             }
   391           delete d;
   392           }
   393         }
   394 
   395         {
   396         bool Modified=false;
   397         int optCount=0;
   398         unsigned int crc[3];
   399         crc[0]=cit.getContentId();
   400         SI::PremiereContentTransmissionDescriptor *pct;
   401         for(SI::Loop::Iterator it; (pct=(SI::PremiereContentTransmissionDescriptor *)cit.eventDescriptors.getNext(it,SI::PremiereContentTransmissionDescriptorTag)); ) {
   402           int nid=pct->getOriginalNetworkId();
   403           int tid=pct->getTransportStreamId();
   404           int sid=pct->getServiceId();
   405           if(SetupPE.FixEpg) {
   406             if(nid==133) {
   407 	      if     (tid==0x03 && sid==0xf0) { tid=0x02; sid=0xe0; }
   408 	      else if(tid==0x03 && sid==0xf1) { tid=0x02; sid=0xe1; }
   409 	      else if(tid==0x03 && sid==0xf5) { tid=0x03; sid=0xdc; }
   410 	      else if(tid==0x04 && sid==0xd2) { tid=0x11; sid=0xe2; }
   411 	      else if(tid==0x11 && sid==0xd3) { tid=0x11; sid=0xe3; }
   412 	      else if(tid==0x01 && sid==0xd4) { tid=0x04; sid=0xe4; }
   413               }
   414             }
   415           tChannelID channelID(Source(),nid,tid,sid);
   416           cChannel *channel=Channels.GetByChannelID(channelID,true);
   417           if(!channel) continue;
   418 
   419           cSchedule *pSchedule=(cSchedule *)Schedules->GetSchedule(channelID);
   420           if(!pSchedule) {
   421              pSchedule=new cSchedule(channelID);
   422              Schedules->Add(pSchedule);
   423              }
   424 
   425           optCount++;
   426           SI::PremiereContentTransmissionDescriptor::StartDayEntry sd;
   427           int index=0;
   428           for(SI::Loop::Iterator it; pct->startDayLoop.getNext(sd,it); ) {
   429             int mjd=sd.getMJD();
   430             SI::PremiereContentTransmissionDescriptor::StartDayEntry::StartTimeEntry st;
   431             for(SI::Loop::Iterator it2; sd.startTimeLoop.getNext(st,it2); ) {
   432               time_t StartTime=st.getStartTime(mjd);
   433               time_t EndTime=StartTime+cit.getDuration();
   434               int runningStatus=(StartTime<now && now<EndTime) ? SI::RunningStatusRunning : ((StartTime-30<now && now<StartTime) ? SI::RunningStatusStartsInAFewSeconds : SI::RunningStatusNotRunning);
   435               bool isOpt=false;
   436               if(index++==0 && nCount>1) isOpt=true;
   437               crc[1]=isOpt ? optCount : 0;
   438               crc[2]=StartTime / STARTTIME_BIAS;
   439               tEventID EventId=((('P'<<8)|'W')<<16) | crc16(0,(unsigned char *)crc,sizeof(crc));
   440 
   441               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))
   442               if(EndTime+Setup.EPGLinger*60<now) {
   443                 d2(printf("(old)\n"))
   444                 continue;
   445                 }
   446 
   447               bool newEvent=false;
   448               cEvent *pEvent=(cEvent *)pSchedule->GetEvent(EventId,-1);
   449               if(!pEvent) {
   450                 d2(printf("(new)\n"))
   451                 pEvent=new cEvent(EventId);
   452                 if(!pEvent) continue;
   453                 newEvent=true;
   454                 }
   455               else {
   456                 d2(printf("(upd)\n"))
   457                 pEvent->SetSeen();
   458                 if(pEvent->TableID()==0x00 || pEvent->Version()==cit.getVersionNumber()) {
   459                   if(pEvent->RunningStatus()!=runningStatus)
   460                     pSchedule->SetRunningStatus(pEvent,runningStatus,channel);
   461                   continue;
   462                   }
   463                 }
   464               pEvent->SetEventID(EventId);
   465               pEvent->SetTableID(Tid);
   466               pEvent->SetVersion(cit.getVersionNumber());
   467               pEvent->SetStartTime(StartTime);
   468               pEvent->SetDuration(cit.getDuration());
   469 
   470               if(ShortEventDescriptor) {
   471                 char buffer[256];
   472                 ShortEventDescriptor->name.getText(buffer,sizeof(buffer));
   473                 if(isOpt) {
   474                   char buffer2[sizeof(buffer)+32];
   475                   snprintf(buffer2,sizeof(buffer2),optPats[SetupPE.OptPat],buffer,optCount);
   476                   pEvent->SetTitle(buffer2);
   477                   }
   478                 else
   479                   pEvent->SetTitle(buffer);
   480                 d2(printf("title: %s\n",pEvent->Title()))
   481                 pEvent->SetShortText(ShortEventDescriptor->text.getText(buffer,sizeof(buffer)));
   482                 }
   483               if(ExtendedEventDescriptors) {
   484                 char buffer[ExtendedEventDescriptors->getMaximumTextLength(": ")+1];
   485                 pEvent->SetDescription(ExtendedEventDescriptors->getText(buffer,sizeof(buffer),": "));
   486                 }
   487               if(order || rating) {
   488                 int len=(pEvent->Description() ? strlen(pEvent->Description()) : 0) +
   489                         (order                 ? strlen(order) : 0) +
   490                         (rating                ? strlen(rating) : 0);
   491                 char buffer[len+32];
   492                 buffer[0]=0;
   493                 if(pEvent->Description()) strcat(buffer,pEvent->Description());
   494                 if(rating)                strcat(buffer,rating);
   495                 if(order)                 strcat(buffer,order);
   496                 pEvent->SetDescription(buffer);
   497                 }
   498 
   499               if(newEvent) pSchedule->AddEvent(pEvent);
   500               pEvent->SetComponents(NULL);
   501               pEvent->FixEpgBugs();
   502               if(pEvent->RunningStatus()!=runningStatus)
   503                 pSchedule->SetRunningStatus(pEvent,runningStatus,channel);
   504               pSchedule->DropOutdated(StartTime,EndTime,Tid,cit.getVersionNumber());
   505               Modified=true;
   506               }
   507             }
   508           if(Modified) {
   509             pSchedule->Sort();
   510             Schedules->SetModified(pSchedule);
   511             }
   512           delete pct;
   513           }
   514         }
   515         delete ExtendedEventDescriptors;
   516         delete ShortEventDescriptor;
   517         free(order);
   518         free(rating);
   519         }
   520       }
   521     }
   522 }
   523 
   524 // --- cPluginPremiereEpg ------------------------------------------------------
   525 
   526 static const char *DESCRIPTION    = trNOOP("Parses extended Premiere EPG data");
   527 
   528 class cPluginPremiereEpg : public cPlugin {
   529 private:
   530   struct {
   531     cFilterPremiereEpg *filter;
   532     cDevice *device;
   533     } epg[MAXDVBDEVICES];
   534 public:
   535   cPluginPremiereEpg(void);
   536   virtual const char *Version(void) { return PluginVersion; }
   537   virtual const char *Description(void) { return tr(DESCRIPTION); }
   538   virtual bool Start(void);
   539   virtual void Stop(void);
   540   virtual cMenuSetupPage *SetupMenu(void);
   541   virtual bool SetupParse(const char *Name, const char *Value);
   542   };
   543 
   544 cPluginPremiereEpg::cPluginPremiereEpg(void)
   545 {
   546   memset(epg,0,sizeof(epg));
   547 }
   548 
   549 bool cPluginPremiereEpg::Start(void)
   550 {
   551 #if APIVERSNUM < 10507
   552   RegisterI18n(Phrases);
   553 #endif
   554   for(int i=0; i<MAXDVBDEVICES; i++) {
   555     cDevice *dev=cDevice::GetDevice(i);
   556     if(dev) {
   557       epg[i].device=dev;
   558       dev->AttachFilter(epg[i].filter=new cFilterPremiereEpg);
   559       isyslog("Attached premiere EPG filter to device %d",i);
   560       }
   561     }
   562   return true;
   563 }
   564 
   565 void cPluginPremiereEpg::Stop(void)
   566 {
   567   for(int i=0; i<MAXDVBDEVICES; i++) {
   568     cDevice *dev=epg[i].device;
   569     if(dev) dev->Detach(epg[i].filter);
   570     delete epg[i].filter;
   571     epg[i].device=0;
   572     epg[i].filter=0;
   573     }
   574 }
   575 
   576 cMenuSetupPage *cPluginPremiereEpg::SetupMenu(void)
   577 {
   578   return new cMenuSetupPremiereEpg;
   579 }
   580 
   581 bool cPluginPremiereEpg::SetupParse(const char *Name, const char *Value)
   582 {
   583   if      (!strcasecmp(Name, "OptionPattern")) SetupPE.OptPat     = atoi(Value);
   584   else if (!strcasecmp(Name, "OrderInfo"))     SetupPE.OrderInfo  = atoi(Value);
   585   else if (!strcasecmp(Name, "RatingInfo"))    SetupPE.RatingInfo = atoi(Value);
   586   else if (!strcasecmp(Name, "FixEpg"))        SetupPE.FixEpg     = atoi(Value);
   587   else return false;
   588   return true;
   589 }
   590 
   591 VDRPLUGINCREATOR(cPluginPremiereEpg); // Don't touch this!