diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | eepg.c | 757 | ||||
-rw-r--r-- | eepg.h | 14 | ||||
-rw-r--r-- | epghandler.c | 41 | ||||
-rw-r--r-- | epghandler.h | 3 | ||||
-rw-r--r-- | equivhandler.c | 265 | ||||
-rw-r--r-- | equivhandler.h | 39 | ||||
-rw-r--r-- | setupeepg.c | 7 | ||||
-rw-r--r-- | setupeepg.h | 17 | ||||
-rw-r--r-- | util.c | 209 | ||||
-rw-r--r-- | util.h | 32 |
11 files changed, 837 insertions, 549 deletions
@@ -65,7 +65,7 @@ DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' ### The object files (add further files here): -OBJS = $(PLUGIN).o dish.o epghandler.o setupeepg.o +OBJS = $(PLUGIN).o dish.o epghandler.o setupeepg.o equivhandler.o util.o ifdef DBG CXXFLAGS += -g @@ -43,6 +43,8 @@ #endif #include "log.h" #include "setupeepg.h" +#include "equivhandler.h" +#include "util.h" #include <map> #include <string> @@ -56,20 +58,6 @@ #define trNOOP(s) (s) #endif -//#define DEBUG -//#define DEBUG2 - -/*#ifdef DEBUG -#define d(x) { (x); } -#else -#define d(x) ; -#endif -#ifdef DEBUG2 -#define d2(x) { (x); } -#else -#define d2(x) ; -#endif*/ - #define PMT_SCAN_TIMEOUT 10 // seconds #define PMT_SCAN_IDLE 3600 // seconds @@ -85,6 +73,7 @@ template <class T> T REALLOC(T Var, size_t Size) } using namespace std; +using namespace util; const char *optPats[] = { "%s", @@ -111,7 +100,7 @@ char *cs_hexdump (int m, const uchar * buf, int n) } cSetupEEPG* SetupPE = cSetupEEPG::getInstance(); - +cEquivHandler* EquivHandler; // --- cMenuSetupPremiereEpg ------------------------------------------------------------ @@ -181,11 +170,8 @@ unsigned int crc16 (unsigned int crc, unsigned char const *p, int len) #define STARTTIME_BIAS (20*60) -static int AvailableSources[32]; -static int NumberOfAvailableSources = 0; static int LastVersionNagra = -1; //currently only used for Nagra, should be stored per transponder, per system -static multimap<string, string> equiChanMap; #ifdef USE_NOEPG @@ -213,7 +199,7 @@ class cFilterEEPG:public cFilter private: int pmtpid, pmtsid, pmtidx, pmtnext; int UnprocessedFormat[HIGHEST_FORMAT + 1]; //stores the pid when a format is detected on this transponder, and that are not processed yet - int nEquivChannels, nChannels, nThemes, nTitles, nSummaries, NumberOfTables, Version; + int nChannels, nThemes, nTitles, nSummaries, NumberOfTables, Version; int TitleCounter, SummaryCounter, NoSummaryCounter, RejectTableId; bool EndChannels, EndThemes; //only used for ?? int MHWStartTime; //only used for MHW1 @@ -261,14 +247,13 @@ protected: virtual int GetSummariesMHW2 (const u_char * Data, int Length); virtual void FreeSummaries (void); virtual void FreeTitles (void); - virtual void PrepareToWriteToSchedule (sChannel * C, cSchedules * s, cSchedule * ps[MAX_EQUIVALENCES]); //gets a channel and returns an array of schedules that WriteToSchedule can write to. Call this routine before a batch of titles with the same ChannelId will be WriteToScheduled; batchsize can be 1 - virtual void FinishWriteToSchedule (sChannel * C, cSchedules * s, cSchedule * ps[MAX_EQUIVALENCES]); - virtual void WriteToSchedule (cSchedule * ps[MAX_EQUIVALENCES], unsigned short int NumberOfEquivalences, - unsigned int EventId, unsigned int StartTime, unsigned int Duration, char *Text, - char *SummText, unsigned short int ThemeId, unsigned short int TableId, - unsigned short int Version, char Rating = 0x00); + //virtual void PrepareToWriteToSchedule (sChannel * C, cSchedules * s, cSchedule * ps/*[MAX_EQUIVALENCES]*/); //gets a channel and returns an array of schedules that WriteToSchedule can write to. Call this routine before a batch of titles with the same ChannelId will be WriteToScheduled; batchsize can be 1 + //virtual void FinishWriteToSchedule (sChannel * C, cSchedules * s, cSchedule * ps[MAX_EQUIVALENCES]); + virtual void WriteToSchedule (tChannelID channelID, cSchedules* s, unsigned int EventId, unsigned int StartTime, + unsigned int Duration, char *Text, char *SummText, unsigned short int ThemeId, + unsigned short int TableId, unsigned short int Version, char Rating = 0x00); virtual void LoadIntoSchedule (void); - virtual void LoadEquivalentChannels (void); + //virtual void LoadEquivalentChannels (void); void ProcessPremiere(const u_char *& Data); public: @@ -361,8 +346,8 @@ struct hufftab { int freesat_decode_error = 0; /* If set an error has occurred during decoding */ -static struct hufftab *tables[2][256]; -static int table_size[2][256]; +static struct hufftab *tables[2][128]; +static int table_size[2][128]; static sNodeH* sky_tables[2]; /** \brief Convert a textual character description into a value @@ -443,6 +428,9 @@ static bool load_freesat_file (int tableid, const char *filename) tables[tableid][from_char][i].value = bin; tables[tableid][from_char][i].next = to_char; tables[tableid][from_char][i].bits = bin_len; + /* char from; unsigned int value; short bits; char next; */ + LogI(2, prep("%02x;%08x;%04x;%02x"), from_char, bin, bin_len, to_char); + free (from); free (to); free (binary); @@ -780,120 +768,13 @@ nextloop1: //here all declarations for global variables over all devices -char *ConfDir; +//char *ConfDir; //unsigned char DecodeErrorText[4096]; //TODO only used for debugging? -int Yesterday; -int YesterdayEpoch; -int YesterdayEpochUTC; - -/* - * Convert local time to UTC - */ -time_t LocalTime2UTC (time_t t) -{ - struct tm *temp; - - temp = gmtime (&t); - temp->tm_isdst = -1; - return mktime (temp); -} - -/* - * Convert UTC to local time - */ -time_t UTC2LocalTime (time_t t) -{ - return 2 * t - LocalTime2UTC (t); -} - -void GetLocalTimeOffset (void) -{ - time_t timeLocal; - struct tm *tmCurrent; - - timeLocal = time (NULL); - timeLocal -= 86400; - tmCurrent = gmtime (&timeLocal); - Yesterday = tmCurrent->tm_wday; - tmCurrent->tm_hour = 0; - tmCurrent->tm_min = 0; - tmCurrent->tm_sec = 0; - tmCurrent->tm_isdst = -1; - YesterdayEpoch = mktime (tmCurrent); - YesterdayEpochUTC = UTC2LocalTime (mktime (tmCurrent)); -} - -void CleanString (unsigned char *String) -{ - -// LogD (1, prep("Unclean: %s"), String); - unsigned char *Src; - unsigned char *Dst; - int Spaces; - int pC; - Src = String; - Dst = String; - Spaces = 0; - pC = 0; - while (*Src) { - // corrections - if (*Src == 0x8c) { // iso-8859-2 LATIN CAPITAL LETTER S WITH ACUTE - *Src = 0xa6; - } - if (*Src == 0x8f) { // iso-8859-2 LATIN CAPITAL LETTER Z WITH ACUTE - *Src = 0xac; - } - - if (*Src!=0x0A && *Src < 0x20) { //don't remove newline - *Src = 0x20; - } - if (*Src == 0x20) { - Spaces++; - if (pC == 0) { - Spaces++; - } - } else { - Spaces = 0; - } - if (Spaces < 2) { - *Dst = *Src; - Dst++; - pC++; - } - Src++; - } - if (Spaces > 0) { - Dst--; - *Dst = 0; - } else { - *Dst = 0; - } -// LogD (1, prep("Clean: %s"), String); -} - -cChannel *GetChannelByID(tChannelID & channelID, bool searchOtherPos) -{ - cChannel *VC = Channels.GetByChannelID(channelID, true); - if(!VC && searchOtherPos){ - //look on other satpositions - for(int i = 0;i < NumberOfAvailableSources;i++){ - channelID = tChannelID(AvailableSources[i], channelID.Nid(), channelID.Tid(), channelID.Sid()); - VC = Channels.GetByChannelID(channelID, true); - if(VC){ - //found this actually on satellite nextdoor... - break; - } - } - } - - return VC; -} - bool cFilterEEPG::GetThemesSKYBOX (void) //TODO can't we read this from the DVB stream? { - string FileName = ConfDir; + string FileName = cSetupEEPG::getInstance()->getConfDir(); FILE *FileThemes; char *Line; char Buffer[256]; @@ -941,7 +822,7 @@ bool cFilterEEPG::GetThemesSKYBOX (void) //TODO can't we read this from the DVB */ bool cFilterEEPG::InitDictionary (void) { - string FileName = ConfDir; + string FileName = cSetupEEPG::getInstance()->getConfDir(); switch (Format) { case SKY_IT: if (sky_tables[0] == NULL) { @@ -965,7 +846,7 @@ bool cFilterEEPG::InitDictionary (void) FileName += "/freesat.t1"; if (!load_freesat_file (1, FileName.c_str())) return false; - FileName = ConfDir; + FileName = cSetupEEPG::getInstance()->getConfDir(); FileName += "/freesat.t2"; return load_freesat_file (2, FileName.c_str()); } else @@ -1001,175 +882,20 @@ void decodeText2 (const unsigned char *from, int len, char *buffer, int buffsize //LogE(5, prep("decodeText2 buffer %s - buffsize %d"), buffer, buffsize); } -void loadEquivalentChannelMap (void) -{ - char Buffer[1024]; - char *Line; - FILE *File; - string FileName = string(ConfDir) + "/" + EEPG_FILE_EQUIV; - multimap<string,string>::iterator it,it2; - pair<multimap<string,string>::iterator,multimap<string,string>::iterator> ret; - - //TODO DPE add code to reload if file is changed - if (equiChanMap.size() > 0) - return; +void sortSchedules(cSchedules * Schedules, tChannelID channelID){ + LogD(3, prep("Start sortEquivalent %s"), *channelID.ToString()); - File = fopen (FileName.c_str(), "r"); - if (File) { - memset (Buffer, 0, sizeof (Buffer)); - char origChanID[256]; - char equiChanID[256]; - char source[256]; - int nid = 0; - int tid = 0; - int sid = 0; - int rid = 0; - while ((Line = fgets (Buffer, sizeof (Buffer), File)) != NULL) { - Line = compactspace (skipspace (stripspace (Line))); - if (!isempty (Line)) { - if (sscanf (Line, "%[^ ] %[^ ] %[^\n]\n", origChanID, equiChanID, source) == 3) { - if (origChanID[0] != '#' && origChanID[0] != ';') { - nid = 0; - tid = 0; - sid = 0; - rid = 0; - if (sscanf (origChanID, "%[^-]-%i -%i -%i ", source, &nid, &tid, &sid) == 4) - if (sscanf (equiChanID, "%[^-]-%i -%i -%i ", source, &nid, &tid, &sid) == 4) { - if (sscanf (origChanID, "%[^-]-%i -%i -%i -%i ", source, &nid, &tid, &sid, &rid) != 5) { - rid = 0; - } - tChannelID OriginalChID = tChannelID (cSource::FromString (source), nid, tid, sid, rid); - bool found = false; - //int i = 0; - cChannel *OriginalChannel = Channels.GetByChannelID (OriginalChID, false); - if (!OriginalChannel) { - LogI(2, prep("Warning, not found epg channel \'%s\' in channels.conf. Equivalency is assumed to be valid, but perhaps you should check the entry in the equivalents file"), origChanID); //TODO: skip this ing? - continue; - } - if (sscanf (equiChanID, "%[^-]-%i -%i -%i ", source, &nid, &tid, &sid) == 4) { - if (sscanf (equiChanID, "%[^-]-%i -%i -%i -%i ", source, &nid, &tid, &sid, &rid) - != 5) { - rid = 0; - } - tChannelID EquivChID = tChannelID (cSource::FromString (source), nid, tid, sid, rid); - cChannel *EquivChannel = Channels.GetByChannelID (EquivChID, false); //TODO use valid function? - if (EquivChannel) { - ret = equiChanMap.equal_range(*OriginalChID.ToString()); - for (it=ret.first; it!=ret.second; ++it) - if ((*it).second == *OriginalChID.ToString()) { - found = true; - break; - } - - if (!found) { - string origCh(*OriginalChID.ToString()); - string equiCh(*EquivChID.ToString()); - equiChanMap.insert(pair<string,string>(origCh.c_str(),equiCh.c_str())); - LogD(4, prep("Found %s equivalent to %s. origCh %s"), *EquivChID.ToString(), *OriginalChID.ToString(), origCh.c_str()); - for ( it2=equiChanMap.begin() ; it2 != equiChanMap.end(); it2++ ) - LogD(3, prep("Original ID %s <-> Equivalent ID %s"), (*it2).first.c_str(), it2->second.c_str()); - } - } else - LogI(0, prep("Warning, not found equivalent channel \'%s\' in channels.conf"), equiChanID); - } - } //if scanf string1 - } //if string1 - } //if scanf - } //if isempty - } //while - fclose (File); - LogD(3, prep("Loaded %i equivalents."), equiChanMap.size()); - for ( it2=equiChanMap.begin() ; it2 != equiChanMap.end(); it2++ ) - LogD(3, prep("Original ID %s <-> Equivalent ID %s"), (*it2).first.c_str(), it2->second.c_str()); - } //if file + cChannel *pChannel = GetChannelByID (channelID, false); + cSchedule *pSchedule; + if (pChannel) { + pSchedule = (cSchedule *) (Schedules->GetSchedule(pChannel, true)); + pSchedule->Sort(); + Schedules->SetModified(pSchedule); + } + if (EquivHandler->getEquiChanMap().count(*channelID.ToString()) > 0) + EquivHandler->sortEquivalents(channelID, Schedules); } -void cFilterEEPG::LoadEquivalentChannels (void) -{ - char Buffer[1024]; - char *Line; - FILE *File; - string FileName = string(ConfDir) + "/" + EEPG_FILE_EQUIV; - - File = fopen (FileName.c_str(), "r"); - if (File) { - memset (Buffer, 0, sizeof (Buffer)); - char origChanID[256]; - char equiChanID[256]; - char source[256]; - int nid; - int tid; - int sid; - int rid; - while ((Line = fgets (Buffer, sizeof (Buffer), File)) != NULL) { - Line = compactspace (skipspace (stripspace (Line))); - if (!isempty (Line)) { - if (sscanf (Line, "%[^ ] %[^ ] %[^\n]\n", origChanID, equiChanID, source) == 3) { - if (origChanID[0] != '#' && origChanID[0] != ';') { - nid = 0; - tid = 0; - sid = 0; - rid = 0; - if (sscanf (origChanID, "%[^-]-%i -%i -%i ", source, &nid, &tid, &sid) == 4) - if (sscanf (equiChanID, "%[^-]-%i -%i -%i ", source, &nid, &tid, &sid) == 4) { - if (sscanf (origChanID, "%[^-]-%i -%i -%i -%i ", source, &nid, &tid, &sid, &rid) != 5) { - rid = 0; - } - tChannelID OriginalChID = tChannelID (cSource::FromString (source), nid, tid, sid, rid); - bool found = false; - int i = 0; - sChannel *C = NULL; - while (i < nChannels && (!found)) { - C = &sChannels[i]; - if (C->Src[0] == (unsigned int)cSource::FromString (source) && C->Nid[0] == nid - && C->Tid[0] == tid && C->Sid[0] == sid) - found = true; - else - i++; - } - if (!found) { - LogI(2, prep("Warning: in equivalence file, cannot find original channel %s. Perhaps you are tuned to another transponder right now."), - origChanID); - } else { - cChannel *OriginalChannel = Channels.GetByChannelID (OriginalChID, false); - if (!OriginalChannel) - LogI(2, prep("Warning, not found epg channel \'%s\' in channels.conf. Equivalence is assumed to be valid, but perhaps you should check the entry in the equivalents file"), origChanID); //TODO: skip this ing? - if (sscanf (equiChanID, "%[^-]-%i -%i -%i ", source, &nid, &tid, &sid) == 4) { - if (sscanf (equiChanID, "%[^-]-%i -%i -%i -%i ", source, &nid, &tid, &sid, &rid) - != 5) { - rid = 0; - } - tChannelID EquivChID = tChannelID (cSource::FromString (source), nid, tid, sid, rid); - cChannel *EquivChannel = Channels.GetByChannelID (EquivChID, false); //TODO use valid function? - if (EquivChannel) { - if (C->NumberOfEquivalences < MAX_EQUIVALENCES) { - C->Src[C->NumberOfEquivalences] = EquivChannel->Source (); - C->Nid[C->NumberOfEquivalences] = EquivChannel->Nid (); - C->Tid[C->NumberOfEquivalences] = EquivChannel->Tid (); - C->Sid[C->NumberOfEquivalences] = EquivChannel->Sid (); - C->NumberOfEquivalences++; - nEquivChannels++; - LogI(3, prep("Added equivalent nr %i with Channel Id %s-%i-%i-%i to channel with id %i."), - C->NumberOfEquivalences, *cSource::ToString (C->Src[C->NumberOfEquivalences - 1]), - C->Nid[C->NumberOfEquivalences - 1], C->Tid[C->NumberOfEquivalences - 1], - C->Sid[C->NumberOfEquivalences - 1], i); - } else - LogE(0, prep("Error, channel with id %i has more than %i equivalences. Increase MAX_EQUIVALENCES."), - i, MAX_EQUIVALENCES); - } else - LogI(0, prep("Warning, not found equivalent channel \'%s\' in channels.conf"), equiChanID); - } - } //else !found - } //if scanf string1 - } //if string1 - } //if scanf - } //if isempty - } //while - fclose (File); - } //if file -} //end of loadequiv - -//end of loadequiv /** @@ -1231,27 +957,28 @@ int cFilterEEPG::GetChannelsMHW (const u_char * Data, int Length, int MHW) //memcpy (C->Name, &Data[pName + 1], 256); pName += (lenName + 1); } - C->NumberOfEquivalences = 1; //there is always an original channel. every equivalence adds 1 - C->Src[0] = Source (); //assume all EPG channels are on same satellite, if not, manage this via equivalents!!! - C->Nid[0] = HILO16 (Channel->NetworkId); - C->Tid[0] = HILO16 (Channel->TransportId); - C->Sid[0] = HILO16 (Channel->ServiceId); - tChannelID channelID = tChannelID (C->Src[0], C->Nid[0], C->Tid[0], C->Sid[0]); + //C->NumberOfEquivalences = 1; //there is always an original channel. every equivalence adds 1 + C->Src = Source (); //assume all EPG channels are on same satellite, if not, manage this via equivalents!!! + C->Nid = HILO16 (Channel->NetworkId); + C->Tid = HILO16 (Channel->TransportId); + C->Sid = HILO16 (Channel->ServiceId); + tChannelID channelID = tChannelID (C->Src, C->Nid, C->Tid, C->Sid); cChannel *VC = GetChannelByID(channelID, true); bool IsFound = (VC); if(IsFound) { - C->Src[0] = VC->Source(); + C->Src = VC->Source(); } CleanString (C->Name); LogI(1, "|% 5d | %-26.26s | %-22.22s | %-3.3s | % 6d |\n", C->ChannelId - , *tChannelID (C->Src[0], C->Nid[0], C->Tid[0], C->Sid[0]).ToString() + , *tChannelID (C->Src, C->Nid, C->Tid, C->Sid).ToString() , C->Name, IsFound ? "YES" : "NO", C->SkyNumber); Off += Size; } //for loop } //else nChannels > MAX_CHANNELS - LoadEquivalentChannels (); + //LoadEquivalentChannels (); + EquivHandler->loadEquivalentChannelMap(); GetLocalTimeOffset (); //reread timing variables, only used for MHW return 2; //obviously, when you get here, channels are read successfully, but since all channels are sent at once, you can stop now } //if nChannels == 0 @@ -1518,32 +1245,32 @@ char *cFilterEEPG::GetSummaryTextNagra (const u_char * DataStart, long int Offse * \param s VDR epg schedules * \param ps pointer to the schedules that WriteToSchedule can write to */ -void cFilterEEPG::PrepareToWriteToSchedule (sChannel * C, cSchedules * s, cSchedule * ps[MAX_EQUIVALENCES]) -{ - for (int eq = 0; eq < C->NumberOfEquivalences; eq++) { - tChannelID channelID = tChannelID (C->Src[eq], C->Nid[eq], C->Tid[eq], C->Sid[eq]); -#ifdef USE_NOEPG - if (allowedEPG (channelID) && (channelID.Valid ())) -#else - if (channelID.Valid ()) //only add channels that are known to vdr -#endif /* NOEPG */ - ps[eq] = s->AddSchedule (channelID); //open a a schedule for each equivalent channel - else { - ps[eq] = NULL; - LogE(5, prep("ERROR: Title block has invalid (equivalent) channel ID: Equivalence: %i, Source:%x, C->Nid:%x,C->Tid:%x,C->Sid:%x."), - eq, C->Src[eq], C->Nid[eq], C->Tid[eq], C->Sid[eq]); - } - } -} - -void cFilterEEPG::FinishWriteToSchedule (sChannel * C, cSchedules * s, cSchedule * ps[MAX_EQUIVALENCES]) -{ - for (int eq = 0; eq < C->NumberOfEquivalences; eq++) - if (ps[eq]) { - ps[eq]->Sort (); - s->SetModified (ps[eq]); - } -} +//void cFilterEEPG::PrepareToWriteToSchedule (sChannel * C, cSchedules * s, cSchedule * ps/*[MAX_EQUIVALENCES]*/) +//{ +// //for (int eq = 0; eq < C->NumberOfEquivalences; eq++) { +// tChannelID channelID = tChannelID (C->Src/*[eq]*/, C->Nid/*[eq]*/, C->Tid/*[eq]*/, C->Sid/*[eq]*/); +//#ifdef USE_NOEPG +// if (allowedEPG (channelID) && (channelID.Valid ())) +//#else +// if (channelID.Valid ()) //only add channels that are known to vdr +//#endif /* NOEPG */ +// ps/*[eq]*/ = s->AddSchedule (channelID); //open a a schedule for each equivalent channel +// else { +// ps/*[eq]*/ = NULL; +//// LogE(5, prep("ERROR: Title block has invalid (equivalent) channel ID: Equivalence: %i, Source:%x, C->Nid:%x,C->Tid:%x,C->Sid:%x."), +//// eq, C->Src[eq], C->Nid[eq], C->Tid[eq], C->Sid[eq]); +// } +// //} +//} + +//void cFilterEEPG::FinishWriteToSchedule (sChannel * C, cSchedules * s, cSchedule * ps[MAX_EQUIVALENCES]) +//{ +// for (int eq = 0; eq < C->NumberOfEquivalences; eq++) +// if (ps[eq]) { +// ps[eq]->Sort (); +// s->SetModified (ps[eq]); +// } +//} /** * \brief write event to schedule @@ -1551,104 +1278,111 @@ void cFilterEEPG::FinishWriteToSchedule (sChannel * C, cSchedules * s, cSchedule * \param Duration the Duration of the event in minutes * \param ps points to array of schedules ps[eq], where eq is equivalence number of the channel. If channelId is invalid then ps[eq]=NULL */ -void cFilterEEPG::WriteToSchedule (cSchedule * ps[MAX_EQUIVALENCES], unsigned short int NumberOfEquivalences, unsigned int EventId, unsigned int StartTime, unsigned int Duration, char *Text, char *SummText, unsigned short int ThemeId, unsigned short int TableId, unsigned short int Version, char Rating) +void cFilterEEPG::WriteToSchedule (tChannelID channelID, cSchedules* pSchedules, unsigned int EventId, unsigned int StartTime, unsigned int Duration, char *Text, char *SummText, unsigned short int ThemeId, unsigned short int TableId, unsigned short int Version, char Rating) { bool WrittenTitle = false; bool WrittenSummary = false; - for (int eq = 0; eq < NumberOfEquivalences; eq++) { - if (ps[eq]) { - cEvent *Event = NULL; +// for (int eq = 0; eq < NumberOfEquivalences; eq++) { + cSchedule* ps; + if (channelID.Valid ()) //only add channels that are known to VDR + ps = pSchedules->AddSchedule (channelID); //open or create new schedule + else { + ps = NULL; + } + + cEvent *Event = NULL; + if (ps/*[eq]*/) { - Event = (cEvent *) ps[eq]->GetEvent (EventId); //since Nagra uses consistent EventIds, try this first + Event = (cEvent *) ps->GetEvent (EventId); //since Nagra uses consistent EventIds, try this first bool TableIdMatches = false; if (Event) TableIdMatches = (Event->TableID() == TableId); if (!Event || !TableIdMatches || abs(Event->StartTime() - (time_t) StartTime) > Duration * 60) //if EventId does not match, or it matched with wrong TableId, then try with StartTime - Event = (cEvent *) ps[eq]->GetEvent (EventId, StartTime); - - cEvent *newEvent = NULL; - if (!Event) { //event is new - Event = newEvent = new cEvent (EventId); - Event->SetSeen (); - } else if (Event->TableID() < TableId) { //existing table may not be overwritten - RejectTableId++; - //esyslog ("EEPGDEBUG: Rejecting Event, existing TableID:%x, new TableID:%x.", Event->TableID (), - // TableId); - Event = NULL; - } + Event = (cEvent *) ps->GetEvent (EventId, StartTime); + } + cEvent *newEvent = NULL; + if (!Event) { //event is new + Event = newEvent = new cEvent (EventId); + Event->SetSeen (); + } else if (Event->TableID() < TableId) { //existing table may not be overwritten + RejectTableId++; + //esyslog ("EEPGDEBUG: Rejecting Event, existing TableID:%x, new TableID:%x.", Event->TableID (), + // TableId); + Event = NULL; + } - if (Event) { - Event->SetEventID (EventId); //otherwise the summary cannot be added later - Event->SetTableID (TableId); //TableID 0 is reserved for external epg, will not be overwritten; the lower the TableID, the more actual it is - Event->SetVersion (Version); //TODO use version and tableID to decide whether to update; TODO add language code - Event->SetStartTime (StartTime); - Event->SetDuration (Duration * 60); - if (Rating) { - Event->SetParentalRating(Rating); - } - char *tmp; - if (Text != 0x00) { - WrittenTitle = true; - CleanString ((uchar *) Text); - Event->SetTitle (Text); + if (Event) { + Event->SetEventID (EventId); //otherwise the summary cannot be added later + Event->SetTableID (TableId); //TableID 0 is reserved for external epg, will not be overwritten; the lower the TableID, the more actual it is + Event->SetVersion (Version); //TODO use version and tableID to decide whether to update; TODO add language code + Event->SetStartTime (StartTime); + Event->SetDuration (Duration * 60); + if (Rating) { + Event->SetParentalRating(Rating); + } + char *tmp; + if (Text != 0x00) { + WrittenTitle = true; + CleanString ((uchar *) Text); + Event->SetTitle (Text); + } + Asprintf (&tmp, "%s - %d\'", Themes[ThemeId], Duration); + Event->SetShortText (tmp); + free(tmp); + //strreplace(t, '|', '\n'); + if (SummText != 0x00) { + WrittenSummary = true; + CleanString ((uchar *) SummText); + + //Add themes and categories epgsearch style + char *theme; + Asprintf (&theme, "%s", Themes[ThemeId]); + if (theme && 0 != strcmp(theme,"")) { + char *category, *genre; + category = NULL; + genre = NULL; + char *split = strchr(theme, '-'); // Look for '-' delim to separate category from genre + if (split){ + *split = 0; + category = theme; + genre = (split[1] == 0x20) ? split + 2 : split + 1; + }else{ + category = theme; } - Asprintf (&tmp, "%s - %d\'", Themes[ThemeId], Duration); - Event->SetShortText (tmp); - free(tmp); - //strreplace(t, '|', '\n'); - if (SummText != 0x00) { - WrittenSummary = true; - CleanString ((uchar *) SummText); - - //Add themes and categories epgsearch style - char *theme; - Asprintf (&theme, "%s", Themes[ThemeId]); - if (theme && 0 != strcmp(theme,"")) { - char *category, *genre; - category = NULL; - genre = NULL; - char *split = strchr(theme, '-'); // Look for '-' delim to separate category from genre - if (split){ - *split = 0; - category = theme; - genre = (split[1] == 0x20) ? split + 2 : split + 1; - }else{ - category = theme; - } - string fmt; - fmt = "%s"; - if (stripspace(category)) { - fmt += "\nCategory: %s"; - } - if (genre) { - fmt += "\nGenre: %s"; - } - Asprintf (&tmp, fmt.c_str(), SummText, category, stripspace (genre)); - - Event->SetDescription (tmp); - free(tmp); - free(theme); + string fmt; + fmt = "%s"; + if (stripspace(category)) { + fmt += "\nCategory: %s"; } - else - Event->SetDescription (SummText); + if (genre) { + fmt += "\nGenre: %s"; } - if (newEvent) - ps[eq]->AddEvent (newEvent); - //newEvent->FixEpgBugs (); causes segfault - } + Asprintf (&tmp, fmt.c_str(), SummText, category, stripspace (genre)); + + Event->SetDescription (tmp); + free(tmp); + free(theme); + } + else + Event->SetDescription (SummText); + } + if (ps && newEvent) + ps->AddEvent (newEvent); + //newEvent->FixEpgBugs (); causes segfault + } /* else esyslog ("EEPG: ERROR, somehow not able to add/update event.");*///at this moment only reports RejectTableId events - if (CheckLevel(4)) { - isyslog ("EEPG: Title:%i, Summary:%i I would put into schedule:", TitleCounter, SummaryCounter); - //isyslog ("C %s-%i-%i-%i\n", *cSource::ToString (C->Src[eq]), C->Nid[eq], C->Tid[eq], C->Sid[eq]); - isyslog ("E %u %u %u 01 FF\n", EventId, StartTime, Duration * 60); - isyslog ("T %s\n", Text); - isyslog ("S %s - %d\'\n", Themes[ThemeId], Duration); - isyslog ("D %s\n", SummText); - isyslog ("e\nc\n.\n"); - } - } //if ps[eq] - } //for eq + if (CheckLevel(4)) { + isyslog ("EEPG: Title:%i, Summary:%i I would put into schedule:", TitleCounter, SummaryCounter); + //isyslog ("C %s-%i-%i-%i\n", *cSource::ToString (C->Src[eq]), C->Nid[eq], C->Tid[eq], C->Sid[eq]); + isyslog ("E %u %u %u 01 FF\n", EventId, StartTime, Duration * 60); + isyslog ("T %s\n", Text); + isyslog ("S %s - %d\'\n", Themes[ThemeId], Duration); + isyslog ("D %s\n", SummText); + isyslog ("e\nc\n.\n"); + } +// } //if ps[eq] +// } //for eq if (WrittenTitle) TitleCounter++; if (WrittenSummary) @@ -1694,8 +1428,8 @@ void cFilterEEPG::GetTitlesNagra (const u_char * Data, int Length, unsigned shor p += 4; //skip Title number sChannel *C = &sChannels[ChannelSeq[ChannelId]]; //find channel - cSchedule *ps[MAX_EQUIVALENCES]; - PrepareToWriteToSchedule (C, s, ps); + //cSchedule *ps = NULL;//[MAX_EQUIVALENCES]; + //PrepareToWriteToSchedule (C, s, ps); for (int i = 0; i < NumberOfTitles; i++) { //process each title within block sTitleNagraGuide *Title = (sTitleNagraGuide *) p; @@ -1745,7 +1479,8 @@ void cFilterEEPG::GetTitlesNagra (const u_char * Data, int Length, unsigned shor if (Themes[Title->ThemeId][0] == 0x00) //if detailed themeid is not known, get global themeid Title->ThemeId &= 0xf0; - WriteToSchedule (ps, C->NumberOfEquivalences, EventId, StartTime, Title->Duration, Text, SummText, + + WriteToSchedule (tChannelID (C->Src, C->Nid, C->Tid, C->Sid), s, EventId, StartTime, Title->Duration, Text, SummText, Title->ThemeId, NAGRA_TABLE_ID, Version); if (Text != NULL) @@ -1783,7 +1518,8 @@ void cFilterEEPG::GetTitlesNagra (const u_char * Data, int Length, unsigned shor p += 30; //next title } //end for titles - FinishWriteToSchedule (C, s, ps); + //FinishWriteToSchedule (C, s, ps); + sortSchedules(s, tChannelID (C->Src, C->Nid, C->Tid, C->Sid)); p = next_p; } while (p < DataEnd); //end of TitleBlock } @@ -1900,17 +1636,17 @@ int cFilterEEPG::GetChannelsNagra (const u_char * Data, int Length) C->ChannelId = j + 1; //Nagra starts numbering at 1 ChannelSeq[C->ChannelId] = j; //fill lookup table to go from channel-id to sequence nr in table; lookup table starts with 0 C->SkyNumber = 0; - C->NumberOfEquivalences = 1; //there is always an original channel. every equivalence adds 1 - C->Src[0] = Source(); //assume all EPG channels are on same satellite, if not, manage this via equivalents!!! - C->Nid[0] = HILO16 (Channel->NetworkId); - C->Tid[0] = HILO16 (Channel->TransportId); - C->Sid[0] = HILO16 (Channel->ServiceId); - tChannelID channelID = tChannelID(C->Src[0], C->Nid[0], C->Tid[0], C->Sid[0]); + //C->NumberOfEquivalences = 1; //there is always an original channel. every equivalence adds 1 + C->Src = Source(); //assume all EPG channels are on same satellite, if not, manage this via equivalents!!! + C->Nid = HILO16 (Channel->NetworkId); + C->Tid = HILO16 (Channel->TransportId); + C->Sid = HILO16 (Channel->ServiceId); + tChannelID channelID = tChannelID(C->Src, C->Nid, C->Tid, C->Sid); cChannel *VC = GetChannelByID(channelID, true); bool IsFound = (VC); if(IsFound) { strncpy((char*)(C->Name), VC->Name (), 64); - C->Src[0] = VC->Source(); + C->Src = VC->Source(); CleanString (C->Name); } else @@ -1968,7 +1704,8 @@ int cFilterEEPG::GetChannelsNagra (const u_char * Data, int Length) } if (p != DataEnd) LogE(0, prep("Warning, possible problem at end of channel table; p = %p, DataEnd = %p"), p, DataEnd); - LoadEquivalentChannels (); + //LoadEquivalentChannels (); + EquivHandler->loadEquivalentChannelMap(); return 2; //obviously, when you get here, channels are read succesfully, but since all channels are sent at once, you can stop now } @@ -2443,7 +2180,8 @@ int cFilterEEPG::GetChannelsSKYBOX (const u_char * Data, int Length) { if (memcmp (InitialChannel, Data, 8) == 0) { //data is the same as initial title - LoadEquivalentChannels (); + //LoadEquivalentChannels (); + EquivHandler->loadEquivalentChannelMap(); return 2; } else { if (nChannels == 0) @@ -2490,13 +2228,13 @@ int cFilterEEPG::GetChannelsSKYBOX (const u_char * Data, int Length) if (ChannelSeq.count (ChannelId) == 0) { //not found C = &sChannels[nChannels]; C->ChannelId = ChannelId; - C->NumberOfEquivalences = 1; //there is always an original channel. every equivalence adds 1 - C->Src[0] = Source (); //assume all EPG channels are on same satellite, if not, manage this via equivalents!!! - C->Nid[0] = Nid; - C->Tid[0] = Tid; - C->Sid[0] = Sid; + //C->NumberOfEquivalences = 1; //there is always an original channel. every equivalence adds 1 + C->Src = Source (); //assume all EPG channels are on same satellite, if not, manage this via equivalents!!! + C->Nid = Nid; + C->Tid = Tid; + C->Sid = Sid; C->SkyNumber = SkyNumber; - tChannelID channelID = tChannelID (C->Src[0], C->Nid[0], C->Tid[0], C->Sid[0]); + tChannelID channelID = tChannelID (C->Src, C->Nid, C->Tid, C->Sid); cChannel *VC = Channels.GetByChannelID (channelID, true); bool IsFound = (VC); if (IsFound) @@ -2756,6 +2494,7 @@ void cFilterEEPG::LoadIntoSchedule (void) int LostSync = 0; remembersummary = -1; + { cSchedulesLock SchedulesLock (true); cSchedules *s = (cSchedules *) cSchedules::Schedules (SchedulesLock); if (s) { @@ -2800,8 +2539,9 @@ void cFilterEEPG::LoadIntoSchedule (void) //channelids are sequentially numbered and sent in MHW1 and MHW2, but not in SKY, so we need to lookup the table index sChannel *C = &sChannels[ChannelSeq[ChannelId]]; //find channel - cSchedule *p[MAX_EQUIVALENCES]; - PrepareToWriteToSchedule (C, s, p); + //cSchedule *p;//[MAX_EQUIVALENCES]; + //PrepareToWriteToSchedule (C, s, p); + tChannelID chanID = tChannelID (C->Src, C->Nid, C->Tid, C->Sid); char rating = 0x00; if ((Format == SKY_IT || Format == SKY_UK) && T->Rating) { //TODO only works on OTV for now @@ -2812,10 +2552,11 @@ void cFilterEEPG::LoadIntoSchedule (void) TableId = T->TableId; } - WriteToSchedule (p, C->NumberOfEquivalences, T->EventId, StartTime, T->Duration / 60, (char *) T->Text, + WriteToSchedule (chanID, s, T->EventId, StartTime, T->Duration / 60, (char *) T->Text, (char *) S->Text, T->ThemeId, TableId, 0, rating); + sortSchedules(s, chanID); - FinishWriteToSchedule (C, s, p); + //FinishWriteToSchedule (C, s, p); //Replays--; //if ((S->NumReplays != 0) && (Replays > 0)) { //when replays are used, all summaries of the replays are stored consecutively; currently only CSAT //j++; //move to next summary @@ -2848,15 +2589,17 @@ void cFilterEEPG::LoadIntoSchedule (void) /* write Title info to schedule */ sChannel *C = &sChannels[ChannelSeq[T->ChannelId]]; //find channel - cSchedule *p[MAX_EQUIVALENCES]; - PrepareToWriteToSchedule (C, s, p); + //cSchedule *p;//[MAX_EQUIVALENCES]; + tChannelID chanID = tChannelID (C->Src, C->Nid, C->Tid, C->Sid); + //PrepareToWriteToSchedule (C, s, p); char rating = 0x00; if ((Format == SKY_IT || Format == SKY_UK) && T->Rating) { //TODO only works on OTV for now rating = T->Rating; } - WriteToSchedule (p, C->NumberOfEquivalences, T->EventId, T->StartTime, T->Duration / 60, (char *) T->Text, + WriteToSchedule (chanID, s, T->EventId, T->StartTime, T->Duration / 60, (char *) T->Text, NULL, T->ThemeId, DEFAULT_TABLE_ID, 0, rating); - FinishWriteToSchedule (C, s, p); + //FinishWriteToSchedule (C, s, p); + sortSchedules(s, chanID); SummariesNotFound++; i++; //move to next title, for this one no summary can be found @@ -2870,11 +2613,12 @@ void cFilterEEPG::LoadIntoSchedule (void) } //while title } // if s else - esyslog ("EEPG Error: could not lock schedules."); + LogE (0, prep("Error: could not lock schedules.")); + }//release ScheduleLock cSchedules::Cleanup (true); //deletes all past events - isyslog ("EEPG: found %i equivalents channels", nEquivChannels); + //isyslog ("EEPG: found %i equivalents channels", nEquivChannels); isyslog ("EEPG: found %i themes", nThemes); isyslog ("EEPG: found %i channels", nChannels); isyslog ("EEPG: found %i titles", nTitles); @@ -2927,74 +2671,10 @@ class cEIT2:public SI::EIT { public: cEIT2 (cSchedules * Schedules, int Source, u_char Tid, const u_char * Data, bool isEITPid = false, bool OnlyRunningStatus = false); -protected: - void updateEquivalent(cSchedules * Schedules, tChannelID channelID, cEvent *pEvent); +//protected: +// void updateEquivalent(cSchedules * Schedules, tChannelID channelID, cEvent *pEvent); }; -void cEIT2::updateEquivalent(cSchedules * Schedules, tChannelID channelID, cEvent *pEvent){ - multimap<string,string>::iterator it; - pair<multimap<string,string>::iterator,multimap<string,string>::iterator> ret; - - LogD(3, prep("Start updateEquivalent %s"), *channelID.ToString()); - - ret = equiChanMap.equal_range(*channelID.ToString()); - for (it=ret.first; it!=ret.second; ++it) { - LogD(1, prep("equivalent channel exists")); - tChannelID equChannelID (tChannelID::FromString((*it).second.c_str())); - cChannel *equChannel = GetChannelByID (equChannelID, false); - if (equChannel) { - LogD(3, prep("found Equivalent channel %s"), *equChannelID.ToString()); - cSchedule *pSchedule = (cSchedule *) Schedules->GetSchedule (equChannel, true); - cEvent *pEqvEvent = (cEvent *) pSchedule->GetEvent (pEvent->EventID(), pEvent->StartTime()); - if (pEqvEvent) { - LogD(1, prep("equivalent event exists")); - if (pEqvEvent == pEvent) { - LogD(1, prep("equal event exists")); - - } else { - LogD(1, prep("remove equivalent")); - pSchedule->DelEvent(pEqvEvent); - cEvent* newEvent = new cEvent (pEvent->EventID()); - newEvent->SetTableID (pEvent->TableID()); - newEvent->SetStartTime (pEvent->StartTime()); - newEvent->SetDuration (pEvent->Duration()); - newEvent->SetVersion (pEvent->Version()); -// newEvent->SetContents(pEvent->Contents()); - newEvent->SetParentalRating(pEvent->ParentalRating()); - newEvent->SetVps (pEvent->Vps()); - newEvent->SetTitle (pEvent->Title ()); - newEvent->SetShortText (pEvent->ShortText ()); - newEvent->SetDescription (pEvent->Description ()); -// newEvent->SetComponents (pEvent->Components()); - newEvent->FixEpgBugs (); - - pSchedule->AddEvent(newEvent); - pSchedule->Sort (); - - } - - } else { - LogD(1, prep("equivalent event does not exist")); - cEvent* newEvent = new cEvent (pEvent->EventID()); - newEvent->SetTableID (pEvent->TableID()); - newEvent->SetStartTime (pEvent->StartTime()); - newEvent->SetDuration (pEvent->Duration()); - newEvent->SetVersion (pEvent->Version()); -// newEvent->SetContents(pEvent->Contents()); - newEvent->SetParentalRating(pEvent->ParentalRating()); - newEvent->SetVps (pEvent->Vps()); - newEvent->SetTitle (pEvent->Title ()); - newEvent->SetShortText (pEvent->ShortText ()); - newEvent->SetDescription (pEvent->Description ()); -// newEvent->SetComponents (pEvent->Components()); - newEvent->FixEpgBugs (); - - pSchedule->AddEvent(newEvent); - pSchedule->Sort (); - } - } - } -} cEIT2::cEIT2 (cSchedules * Schedules, int Source, u_char Tid, const u_char * Data, bool isEITPid, bool OnlyRunningStatus) : SI::EIT (Data, false) @@ -3572,7 +3252,7 @@ cEIT2::cEIT2 (cSchedules * Schedules, int Source, u_char Tid, const u_char * Dat } } #endif /* DDEPGENTRY */ - updateEquivalent(Schedules, channel->GetChannelID(), pEvent); + EquivHandler->updateEquivalent(Schedules, channel->GetChannelID(), pEvent); } if (Empty && Tid == 0x4E && getSectionNumber () == 0) // ETR 211: an empty entry in section 0 of table 0x4E means there is currently no event running @@ -3584,10 +3264,9 @@ cEIT2::cEIT2 (cSchedules * Schedules, int Source, u_char Tid, const u_char * Dat return; } if (Modified) { - pSchedule->Sort (); if (!HasExternalData) pSchedule->DropOutdated (SegmentStart, SegmentEnd, Tid, getVersionNumber ()); - Schedules->SetModified (pSchedule); + sortSchedules(Schedules, channel->GetChannelID()); } LogD(4, prep("end of cEIT2")); @@ -3602,7 +3281,7 @@ void cFilterEEPG::ProcessNextFormat (bool FirstTime = false) esyslog ("EEPGDEBUG: Format %i on pid %x", i, UnprocessedFormat[i]); */ if (!FirstTime) { - isyslog ("EEPG: found %i equivalents channels", nEquivChannels); + //isyslog ("EEPG: found %i equivalents channels", equiChanMap.size()); isyslog ("EEPG: found %i themes", nThemes); isyslog ("EEPG: found %i channels", nChannels); isyslog ("EEPG: found %i titles", nTitles); @@ -3644,7 +3323,7 @@ void cFilterEEPG::ProcessNextFormat (bool FirstTime = false) if (SetupPE->ProcessEIT && !UnprocessedFormat[EIT] && !UnprocessedFormat[FREEVIEW] && !UnprocessedFormat[DISH_BEV]) { UnprocessedFormat[EIT] = EIT_PID; - loadEquivalentChannelMap(); + EquivHandler->loadEquivalentChannelMap(); } //now start looking for next format to process @@ -3671,7 +3350,6 @@ void cFilterEEPG::ProcessNextFormat (bool FirstTime = false) memset (&InitialSummary, 0, 64); NagraCounter = 0; Version = -1; //because 0 can be a valid version number... - nEquivChannels = 0; nChannels = 0; nThemes = 0; EndChannels = false; @@ -4141,8 +3819,6 @@ void cFilterEEPG::Process (u_short Pid, u_char Tid, const u_char * Data, int Len } //closes SOURCE() } //end of closing -// --- cPluginEEPG ------------------------------------------------------ - void cFilterEEPG::ProcessPremiere(const u_char *& Data) { @@ -4418,6 +4094,7 @@ void cFilterEEPG::ProcessPremiere(const u_char *& Data) } +// --- cPluginEEPG ------------------------------------------------------ class cPluginEEPG:public cPlugin { @@ -4451,7 +4128,7 @@ cPluginEEPG::cPluginEEPG (void) void cPluginEEPG::CheckCreateFile(const char* Name, const char *fileContent[]) { FILE *File; - string FileName = string(ConfDir) + "/" + Name; + string FileName = string(cSetupEEPG::getInstance()->getConfDir()) + "/" + Name; File = fopen(FileName.c_str(), "r"); if (File == NULL) { LogE (0, prep("Error opening file '%s', %s"), FileName.c_str(), strerror (errno)); @@ -4485,12 +4162,12 @@ bool cPluginEEPG::Start (void) isyslog ("Attached EEPG filter to device %d", i); } } - ConfDir = NULL; + char *ConfDir = NULL; // Initialize any background activities the plugin shall perform. DIR *ConfigDir; - if (ConfDir == NULL) { - Asprintf (&ConfDir, "%s/eepg", cPlugin::ConfigDirectory ()); - } + //if (ConfDir == NULL) { + Asprintf (&ConfDir, "%s/eepg", cPlugin::ConfigDirectory ()); + //} ConfigDir = opendir (ConfDir); if (ConfigDir == NULL) { esyslog ("EEPG: Error opening directory '%s', %s", ConfDir, strerror (errno)); @@ -4500,6 +4177,8 @@ bool cPluginEEPG::Start (void) isyslog ("EEPG: Success creating directory '%s'", ConfDir); } } + cSetupEEPG::getInstance()->setConfDir(ConfDir); + CheckCreateFile(EEPG_FILE_EQUIV, FileEquivalences); CheckCreateFile("sky_it.dict", SkyItDictionary); CheckCreateFile("sky_uk.dict", SkyUkDictionary); @@ -4530,7 +4209,11 @@ bool cPluginEEPG::Start (void) #if APIVERSNUM > 10725 new cEEpgHandler(); #endif + EquivHandler = new cEquivHandler(); + if (ConfDir) { + free (ConfDir); + } closedir(ConfigDir); return true; } @@ -4547,15 +4230,19 @@ void cPluginEEPG::Stop (void) } // Clean up after yourself! - if (ConfDir) { - free (ConfDir); - } +// if (ConfDir) { +// free (ConfDir); +// } if (sky_tables[0]) { free(sky_tables[0]); } if (sky_tables[1]) { free(sky_tables[1]); } + if (EquivHandler) { + delete EquivHandler; + } + } cMenuSetupPage *cPluginEEPG::SetupMenu (void) @@ -1,13 +1,11 @@ //#define DEBUG false //#define DEBUG_STARTTIME false -#define EEPG_FILE_EQUIV "eepg.equiv" - #define MAX_THEMES 2046 //this should always be >=256, or Nagra will go wrong!! #define MAX_CHANNELS 2048 #define MAX_TITLES 262144 -#define MAX_EQUIVALENCES 8 //the number of equivalences one channel can have +//#define MAX_EQUIVALENCES 8 //the number of equivalences one channel can have //Formats (need to be consecutively numbered): //#define PREMIERE 0 @@ -53,11 +51,11 @@ typedef struct { unsigned short int ChannelId; unsigned short int SkyNumber; - unsigned short int NumberOfEquivalences;//original channel sets this value to 1, every equivalent channel adds 1 - unsigned int Src[MAX_EQUIVALENCES]; - unsigned short int Nid[MAX_EQUIVALENCES]; - unsigned short int Tid[MAX_EQUIVALENCES]; - unsigned short int Sid[MAX_EQUIVALENCES]; + //unsigned short int NumberOfEquivalences;//original channel sets this value to 1, every equivalent channel adds 1 + unsigned int Src;//[MAX_EQUIVALENCES]; + unsigned short int Nid;//[MAX_EQUIVALENCES]; + unsigned short int Tid;//[MAX_EQUIVALENCES]; + unsigned short int Sid;//[MAX_EQUIVALENCES]; unsigned char Name[64]; } sChannel; diff --git a/epghandler.c b/epghandler.c index 2e50c33..ecf5de9 100644 --- a/epghandler.c +++ b/epghandler.c @@ -8,14 +8,17 @@ #include "epghandler.h" #if APIVERSNUM > 10725 #include "log.h" +#include "equivhandler.h" #include <vdr/sources.h> cEEpgHandler::cEEpgHandler() { LogD(4, prep("cEEpgHandler()")); - + equivHandler = new cEquivHandler(); } cEEpgHandler::~cEEpgHandler() { + delete equivHandler; + equivHandler = NULL; } bool cEEpgHandler::HandleEitEvent(cSchedule* Schedule, @@ -26,6 +29,19 @@ bool cEEpgHandler::HandleEitEvent(cSchedule* Schedule, int nid = Schedule->ChannelID().Nid(); if ((nid >= 0x1001 && nid <= 0x100B) || nid == 0x101 || nid == 0x100) return true; + + //TODO!!! not for commit upsteram + if (EitEvent->getDurationHour() > 10) { + LogD(3, prep("Event longer than 10h Duration:%d DurationHour:%d StartTimeHour:%d"), EitEvent->getDuration(), EitEvent->getDurationHour(), EitEvent->getStartTimeHour()); + const cEvent* exEvent = Schedule->GetEventAround(EitEvent->getStartTime()+EitEvent->getDuration()/2); + if (exEvent) { + LogD(3, prep("10h Existing event %s startTime %d"), exEvent->Title(), exEvent->StartTime()); + return true; + } + } + //if (EitEvent->getDurationHour() > 3) +// return true; + return false; // return true; } @@ -107,6 +123,19 @@ bool cEEpgHandler::HandleEvent(cEvent* Event) { if (!Event->Description() && !origDescription.empty()) { Event->SetDescription(origDescription.c_str()); } + + if (equivHandler->getEquiChanMap().count(*Event->ChannelID().ToString()) <= 0) + return true; + + equivHandler->updateEquivalent(Event->ChannelID(), Event); + +// cSchedulesLock SchedulesLock (true); +// cSchedules *s = (cSchedules *) cSchedules::Schedules (SchedulesLock); +// if (s) { +// equivHandler->updateEquivalent(s, Event->ChannelID(), Event); +// } else +// LogE (0, prep("Error: could not lock schedules.")); + //TODO just to see the difference //else if (!origDescription.empty() && !origDescription.compare(Event->Description())) { // origDescription.append(" | EIT: "); @@ -118,7 +147,17 @@ bool cEEpgHandler::HandleEvent(cEvent* Event) { } bool cEEpgHandler::SortSchedule(cSchedule* Schedule) { + Schedule->Sort(); + + //NOK +// cSchedulesLock SchedulesLock (true); +// cSchedules *s = (cSchedules *) cSchedules::Schedules (SchedulesLock); +// if (s) { +// equivHandler->sortEquivalents(Schedule->ChannelID(), s); +// } else +// LogE (0, prep("Error: could not lock schedules.")); + return true; } diff --git a/epghandler.h b/epghandler.h index 61f295b..e1c6915 100644 --- a/epghandler.h +++ b/epghandler.h @@ -12,6 +12,8 @@ #include <vdr/epg.h> #include <string> +class cEquivHandler; + class cEEpgHandler : public cEpgHandler { public: cEEpgHandler(); @@ -35,6 +37,7 @@ public: private: std::string origShortText; std::string origDescription; + cEquivHandler* equivHandler; }; #endif /*APIVERSNUM > 10725*/ diff --git a/equivhandler.c b/equivhandler.c new file mode 100644 index 0000000..b10c004 --- /dev/null +++ b/equivhandler.c @@ -0,0 +1,265 @@ +/* + * equivhandler.cpp + * + * Created on: 19.5.2012 + * Author: d.petrovski + */ + +#include "equivhandler.h" +#include "setupeepg.h" +#include "log.h" +#include "util.h" + +#include <string> + +using namespace util; + +multimap<string, string> cEquivHandler::equiChanMap; +long cEquivHandler::equiChanFileTime = 0; + +cEquivHandler::cEquivHandler() +{ + loadEquivalentChannelMap(); +} + +cEquivHandler::~cEquivHandler() +{ + // TODO Auto-generated destructor stub +} + +void cEquivHandler::loadEquivalentChannelMap (void) +{ + char Buffer[1024]; + char *Line; + FILE *File; + string FileName = string(cSetupEEPG::getInstance()->getConfDir()) + "/" + EEPG_FILE_EQUIV; + multimap<string,string>::iterator it,it2; + pair<multimap<string,string>::iterator,multimap<string,string>::iterator> ret; + + //Test if file is changed and reload + struct stat st; + if (stat(FileName.c_str(), &st)) { + LogE(0, prep("Error obtaining stats for '%s' "), FileName.c_str()); + return; + } + + if (equiChanMap.size() > 0 && equiChanFileTime == st.st_mtim.tv_nsec) + return; + else + equiChanMap.clear(); + + + File = fopen (FileName.c_str(), "r"); + if (File) { + memset (Buffer, 0, sizeof (Buffer)); + char origChanID[256]; + char equiChanID[256]; + char source[256]; + int nid = 0; + int tid = 0; + int sid = 0; + int rid = 0; + while ((Line = fgets (Buffer, sizeof (Buffer), File)) != NULL) { + Line = compactspace (skipspace (stripspace (Line))); + if (!isempty (Line)) { + if (sscanf (Line, "%[^ ] %[^ ] %[^\n]\n", origChanID, equiChanID, source) == 3) { + if (origChanID[0] != '#' && origChanID[0] != ';') { + nid = 0; + tid = 0; + sid = 0; + rid = 0; + if (sscanf (origChanID, "%[^-]-%i -%i -%i ", source, &nid, &tid, &sid) == 4) + if (sscanf (equiChanID, "%[^-]-%i -%i -%i ", source, &nid, &tid, &sid) == 4) { + if (sscanf (origChanID, "%[^-]-%i -%i -%i -%i ", source, &nid, &tid, &sid, &rid) != 5) { + rid = 0; + } + tChannelID OriginalChID = tChannelID (cSource::FromString (source), nid, tid, sid, rid); + bool found = false; + //int i = 0; + cChannel *OriginalChannel = Channels.GetByChannelID (OriginalChID, false); + if (!OriginalChannel) { + LogI(2, prep("Warning, not found epg channel \'%s\' in channels.conf. Equivalency is assumed to be valid, but perhaps you should check the entry in the equivalents file"), origChanID); //TODO: skip this ing? + continue; + } + if (sscanf (equiChanID, "%[^-]-%i -%i -%i ", source, &nid, &tid, &sid) == 4) { + if (sscanf (equiChanID, "%[^-]-%i -%i -%i -%i ", source, &nid, &tid, &sid, &rid) + != 5) { + rid = 0; + } + tChannelID EquivChID = tChannelID (cSource::FromString (source), nid, tid, sid, rid); + cChannel *EquivChannel = Channels.GetByChannelID (EquivChID, false); //TODO use valid function? + if (EquivChannel) { + ret = equiChanMap.equal_range(*OriginalChID.ToString()); + for (it=ret.first; it!=ret.second; ++it) + if ((*it).second == *OriginalChID.ToString()) { + found = true; + break; + } + + if (!found) { + string origCh(*OriginalChID.ToString()); + string equiCh(*EquivChID.ToString()); + equiChanMap.insert(pair<string,string>(origCh.c_str(),equiCh.c_str())); + LogD(4, prep("Found %s equivalent to %s. origCh %s"), *EquivChID.ToString(), *OriginalChID.ToString(), origCh.c_str()); + for ( it2=equiChanMap.begin() ; it2 != equiChanMap.end(); it2++ ) + LogD(3, prep("Original ID %s <-> Equivalent ID %s"), (*it2).first.c_str(), it2->second.c_str()); + } + } else + LogI(0, prep("Warning, not found equivalent channel \'%s\' in channels.conf"), equiChanID); + } + } //if scanf string1 + } //if string1 + } //if scanf + } //if isempty + } //while + fclose (File); + equiChanFileTime = st.st_mtim.tv_nsec; + LogD(2, prep("Loaded %i equivalents."), equiChanMap.size()); + for ( it2=equiChanMap.begin() ; it2 != equiChanMap.end(); it2++ ) + LogD(2, prep("Original ID %s <-> Equivalent ID %s"), (*it2).first.c_str(), it2->second.c_str()); + } //if file +} + +void cEquivHandler::updateEquivalent(cSchedules * Schedules, tChannelID channelID, cEvent *pEvent){ + multimap<string,string>::iterator it; + pair<multimap<string,string>::iterator,multimap<string,string>::iterator> ret; + + LogD(2, prep("Start updateEquivalent %s"), *channelID.ToString()); + + ret = equiChanMap.equal_range(*channelID.ToString()); + for (it=ret.first; it!=ret.second; ++it) { + LogD(2, prep("equivalent channel exists")); + tChannelID equChannelID (tChannelID::FromString((*it).second.c_str())); + cChannel *equChannel = GetChannelByID (equChannelID, false); + if (equChannel) { + LogD(2, prep("found Equivalent channel %s"), *equChannelID.ToString()); + cSchedule *pSchedule = (cSchedule *) Schedules->GetSchedule (equChannel, true); + cEvent *pEqvEvent = (cEvent *) pSchedule->GetEvent (pEvent->EventID(), pEvent->StartTime()); + if (pEqvEvent) { + LogD(3, prep("equivalent event exists")); + if (pEqvEvent == pEvent) { + LogD(3, prep("equal event exists")); + + } else { + LogD(2, prep("remove equivalent")); + pSchedule->DelEvent(pEqvEvent); + cEvent* newEvent = new cEvent (pEvent->EventID()); + newEvent->SetTableID (pEvent->TableID()); + newEvent->SetStartTime (pEvent->StartTime()); + newEvent->SetDuration (pEvent->Duration()); + newEvent->SetVersion (pEvent->Version()); +// newEvent->SetContents(pEvent->Contents()); + newEvent->SetParentalRating(pEvent->ParentalRating()); + newEvent->SetVps (pEvent->Vps()); + newEvent->SetTitle (pEvent->Title ()); + newEvent->SetShortText (pEvent->ShortText ()); + newEvent->SetDescription (pEvent->Description ()); +// newEvent->SetComponents (pEvent->Components()); + newEvent->FixEpgBugs (); + + pSchedule->AddEvent(newEvent); + + } + + } else { + LogD(3, prep("equivalent event does not exist")); + cEvent* newEvent = new cEvent (pEvent->EventID()); + newEvent->SetTableID (pEvent->TableID()); + newEvent->SetStartTime (pEvent->StartTime()); + newEvent->SetDuration (pEvent->Duration()); + newEvent->SetVersion (pEvent->Version()); +// newEvent->SetContents(pEvent->Contents()); + newEvent->SetParentalRating(pEvent->ParentalRating()); + newEvent->SetVps (pEvent->Vps()); + newEvent->SetTitle (pEvent->Title ()); + newEvent->SetShortText (pEvent->ShortText ()); + newEvent->SetDescription (pEvent->Description ()); +// newEvent->SetComponents (pEvent->Components()); + newEvent->FixEpgBugs (); + + pSchedule->AddEvent(newEvent); + + } + } + } +} + +void cEquivHandler::updateEquivalent(tChannelID channelID, cEvent *pEvent){ + multimap<string,string>::iterator it; + pair<multimap<string,string>::iterator,multimap<string,string>::iterator> ret; + + LogD(2, prep("Start updateEquivalent %s"), *channelID.ToString()); + + ret = equiChanMap.equal_range(*channelID.ToString()); + for (it=ret.first; it!=ret.second; ++it) { + LogD(2, prep("equivalent channel exists")); + tChannelID equChannelID (tChannelID::FromString((*it).second.c_str())); + cEvent* newEvent = new cEvent (pEvent->EventID()); + newEvent->SetTableID (pEvent->TableID()); + newEvent->SetStartTime (pEvent->StartTime()); + newEvent->SetDuration (pEvent->Duration()); + newEvent->SetVersion (pEvent->Version()); +// newEvent->SetContents(pEvent->Contents()); + newEvent->SetParentalRating(pEvent->ParentalRating()); + newEvent->SetVps (pEvent->Vps()); + newEvent->SetTitle (pEvent->Title ()); + newEvent->SetShortText (pEvent->ShortText ()); + newEvent->SetDescription (pEvent->Description ()); +// newEvent->SetComponents (pEvent->Components()); + AddEvent(newEvent, equChannelID); + } +} + + +//cSchedule * findFisrtSchedule (cSchedule * Schedule) { +// if (Schedule->Prev()) +// return findFisrtSchedule((cSchedule *)Schedule->Prev()); +// else +// return Schedule; +//} +// +//cSchedule * findSchedule (cSchedule * Schedule, tChannelID channelID) { +// if (Schedule->ChannelID() == channelID) +// return Schedule; +// +// if (Schedule->Next()) +// return findSchedule((cSchedule *)Schedule->Next(), channelID); +// else +// return NULL; +//} +// +//cSchedule * findEqvSchedule (cSchedule * Schedule, tChannelID channelID) { +// cSchedule* foundSchedule = findSchedule(findFisrtSchedule(Schedule),channelID); +// +// if (foundSchedule) +// return foundSchedule; +// +// cSchedule* sch = new cSchedule(channelID); +// Schedule->Insert(sch); +// return sch; +//} + + +void cEquivHandler::sortEquivalents(tChannelID channelID, cSchedules* Schedules) +{ + multimap<string, string>::iterator it; + pair < multimap < string, string > ::iterator, multimap < string, string + > ::iterator > ret; + LogD(2, prep("sortEquivalents for channel %s count: %d"), *channelID.ToString(), cEquivHandler::getEquiChanMap().count(*channelID.ToString())); + + ret = equiChanMap.equal_range(*channelID.ToString()); + for (it = ret.first; it != ret.second; ++it) + { + LogD(3, prep("equivalent channel exists")); + tChannelID equChannelID(tChannelID::FromString((*it).second.c_str())); + cChannel* pChannel = GetChannelByID(equChannelID, false); + if (pChannel) + { + LogD(2, prep("found Equivalent channel %s"), *equChannelID.ToString()); + cSchedule* pSchedule = (cSchedule *) Schedules->GetSchedule(pChannel, true); + + pSchedule->Sort(); + Schedules->SetModified(pSchedule); + } + } +} diff --git a/equivhandler.h b/equivhandler.h new file mode 100644 index 0000000..7e7cad7 --- /dev/null +++ b/equivhandler.h @@ -0,0 +1,39 @@ +/* + * equivhandler.h + * + * Created on: 19.5.2012 + * Author: d.petrovski + */ + +#ifndef EQUIVHANDLER_H_ +#define EQUIVHANDLER_H_ + +#include <vdr/epg.h> +#include <vdr/channels.h> +#include <map> +#include <string> + +#define EEPG_FILE_EQUIV "eepg.equiv" + +using namespace std; + +class cEquivHandler +{ +public: + cEquivHandler(); + virtual ~cEquivHandler(); + + void loadEquivalentChannelMap (void); + void updateEquivalent(cSchedules * Schedules, tChannelID channelID, cEvent *pEvent); + void updateEquivalent(tChannelID channelID, cEvent *pEvent); + void sortEquivalents(tChannelID channelID, cSchedules* Schedules); + + static multimap<string, string> getEquiChanMap() { return cEquivHandler::equiChanMap; }; + +private: + static multimap<string, string> equiChanMap; + static long equiChanFileTime; + +}; + +#endif /* EQUIVHANDLER_H_ */ diff --git a/setupeepg.c b/setupeepg.c index 3738227..54f8243 100644 --- a/setupeepg.c +++ b/setupeepg.c @@ -23,14 +23,13 @@ cSetupEEPG::cSetupEEPG (void) #ifdef DEBUG LogLevel = 0; #endif - } cSetupEEPG* cSetupEEPG::getInstance() { - if (!_setupEEPG) - _setupEEPG = new cSetupEEPG(); + if (!_setupEEPG) + _setupEEPG = new cSetupEEPG(); - return _setupEEPG; + return _setupEEPG; } diff --git a/setupeepg.h b/setupeepg.h index f5e342a..4c30ede 100644 --- a/setupeepg.h +++ b/setupeepg.h @@ -7,6 +7,7 @@ #ifndef SETUPEEPG_H_ #define SETUPEEPG_H_ +#include <string.h> class cSetupEEPG { @@ -24,12 +25,28 @@ public: public: static cSetupEEPG* getInstance(); + char* getConfDir() const + { + return ConfDir; + } + + void setConfDir(char* confDir) + { + if (ConfDir) + delete ConfDir; + ConfDir = new char[strlen(confDir)+1]; + strcpy(ConfDir, confDir); + } + private: cSetupEEPG (void); cSetupEEPG(cSetupEEPG const&); // copy constructor is private cSetupEEPG& operator=(cSetupEEPG const&); // assignment operator is private static cSetupEEPG* _setupEEPG; +private: + char *ConfDir; + }; #endif /* SETUPEEPG_H_ */ @@ -0,0 +1,209 @@ +/* + * util.c + * + * Created on: 23.5.2012 + * Author: d.petrovski + */ +#include "util.h" +#include <vdr/channels.h> +#include <vdr/thread.h> +#include <vdr/epg.h> + +namespace util +{ + +int AvailableSources[32]; +int NumberOfAvailableSources = 0; + +int Yesterday; +int YesterdayEpoch; +int YesterdayEpochUTC; + +cChannel *GetChannelByID(tChannelID & channelID, bool searchOtherPos) +{ + cChannel *VC = Channels.GetByChannelID(channelID, true); + if(!VC && searchOtherPos){ + //look on other satpositions + for(int i = 0;i < NumberOfAvailableSources;i++){ + channelID = tChannelID(AvailableSources[i], channelID.Nid(), channelID.Tid(), channelID.Sid()); + VC = Channels.GetByChannelID(channelID, true); + if(VC){ + //found this actually on satellite nextdoor... + break; + } + } + } + + return VC; +} + +/* + * Convert local time to UTC + */ +time_t LocalTime2UTC (time_t t) +{ + struct tm *temp; + + temp = gmtime (&t); + temp->tm_isdst = -1; + return mktime (temp); +} + +/* + * Convert UTC to local time + */ +time_t UTC2LocalTime (time_t t) +{ + return 2 * t - LocalTime2UTC (t); +} + +void GetLocalTimeOffset (void) +{ + time_t timeLocal; + struct tm *tmCurrent; + + timeLocal = time (NULL); + timeLocal -= 86400; + tmCurrent = gmtime (&timeLocal); + Yesterday = tmCurrent->tm_wday; + tmCurrent->tm_hour = 0; + tmCurrent->tm_min = 0; + tmCurrent->tm_sec = 0; + tmCurrent->tm_isdst = -1; + YesterdayEpoch = mktime (tmCurrent); + YesterdayEpochUTC = UTC2LocalTime (mktime (tmCurrent)); +} + +void CleanString (unsigned char *String) +{ + +// LogD (1, prep("Unclean: %s"), String); + unsigned char *Src; + unsigned char *Dst; + int Spaces; + int pC; + Src = String; + Dst = String; + Spaces = 0; + pC = 0; + while (*Src) { + // corrections + if (*Src == 0x8c) { // iso-8859-2 LATIN CAPITAL LETTER S WITH ACUTE + *Src = 0xa6; + } + if (*Src == 0x8f) { // iso-8859-2 LATIN CAPITAL LETTER Z WITH ACUTE + *Src = 0xac; + } + + if (*Src!=0x0A && *Src < 0x20) { //don't remove newline + *Src = 0x20; + } + if (*Src == 0x20) { + Spaces++; + if (pC == 0) { + Spaces++; + } + } else { + Spaces = 0; + } + if (Spaces < 2) { + *Dst = *Src; + Dst++; + pC++; + } + Src++; + } + if (Spaces > 0) { + Dst--; + *Dst = 0; + } else { + *Dst = 0; + } +// LogD (1, prep("Clean: %s"), String); +} + +// --- cAddEventThread ---------------------------------------- +// Taken from VDR EPGFixer Plug-in +// http://projects.vdr-developer.org/projects/plg-epgfixer +// by Matti Lehtimaki + +class cAddEventListItem : public cListObject +{ +protected: + cEvent *event; + tChannelID channelID; +public: + cAddEventListItem(cEvent *Event, tChannelID ChannelID) { event = Event; channelID = ChannelID; } + tChannelID GetChannelID() { return channelID; } + cEvent *GetEvent() { return event; } + ~cAddEventListItem() { } +}; + +class cAddEventThread : public cThread +{ +private: + cTimeMs LastHandleEvent; + cList<cAddEventListItem> *list; + enum { INSERT_TIMEOUT_IN_MS = 10000 }; +protected: + virtual void Action(void); +public: + cAddEventThread(void); + ~cAddEventThread(void); + void AddEvent(cEvent *Event, tChannelID ChannelID); +}; + +cAddEventThread::cAddEventThread(void) +:cThread("cAddEventThread"), LastHandleEvent() +{ + list = new cList<cAddEventListItem>; +} + +cAddEventThread::~cAddEventThread(void) +{ + LOCK_THREAD; + list->cList::Clear(); + Cancel(3); +} + +void cAddEventThread::Action(void) +{ + SetPriority(19); + while (Running() && !LastHandleEvent.TimedOut()) { + cAddEventListItem *e = NULL; + cSchedulesLock SchedulesLock(true, 10); + cSchedules *schedules = (cSchedules *)cSchedules::Schedules(SchedulesLock); + Lock(); + while (schedules && (e = list->First()) != NULL) { + cSchedule *schedule = (cSchedule *)schedules->GetSchedule(Channels.GetByChannelID(e->GetChannelID()), true); + schedule->AddEvent(e->GetEvent()); + EpgHandlers.SortSchedule(schedule); + EpgHandlers.DropOutdated(schedule, e->GetEvent()->StartTime(), e->GetEvent()->EndTime(), e->GetEvent()->TableID(), e->GetEvent()->Version()); + list->Del(e); + } + Unlock(); + cCondWait::SleepMs(10); + } +} + +void cAddEventThread::AddEvent(cEvent *Event, tChannelID ChannelID) +{ + LOCK_THREAD; + list->Add(new cAddEventListItem(Event, ChannelID)); + LastHandleEvent.Set(INSERT_TIMEOUT_IN_MS); +} + +static cAddEventThread AddEventThread; + +// --- + +void AddEvent(cEvent *Event, tChannelID ChannelID) +{ + AddEventThread.AddEvent(Event, ChannelID); + if (!AddEventThread.Active()) + AddEventThread.Start(); +} + + +} + @@ -0,0 +1,32 @@ +/* + * util.h + * + * Created on: 23.5.2012 + * Author: d.petrovski + */ + +#ifndef UTIL_H_ +#define UTIL_H_ +#include <time.h> +class cChannel; +struct tChannelID; +class cEvent; + +namespace util +{ +extern int AvailableSources[32]; +extern int NumberOfAvailableSources; + +extern int Yesterday; +extern int YesterdayEpoch; +extern int YesterdayEpochUTC; + +void AddEvent(cEvent *event, tChannelID ChannelID); + +cChannel *GetChannelByID(tChannelID & channelID, bool searchOtherPos); +time_t LocalTime2UTC (time_t t); +time_t UTC2LocalTime (time_t t); +void GetLocalTimeOffset (void); +void CleanString (unsigned char *String); +} +#endif /* UTIL_H_ */ |