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