summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitar Petrovski <dimeptr@gmail.com>2018-08-11 12:56:46 (GMT)
committerDimitar Petrovski <dimeptr@gmail.com>2018-08-11 12:56:46 (GMT)
commitefbf22b18d2509ca8c5bccdb1894661fe8d888d1 (patch)
tree4f3393897cea4afd912ee1e9d3cab4d5644aff28
parent9cd9a75a061ed301378e8102b726549f5a0e672d (diff)
parentca0c9dda448ffe0cd71e85cbc5b1f9c10203e1ad (diff)
downloadvdr-plugin-eepg-efbf22b18d2509ca8c5bccdb1894661fe8d888d1.tar.gz
vdr-plugin-eepg-efbf22b18d2509ca8c5bccdb1894661fe8d888d1.tar.bz2
Merge branch 'experimental'
-rw-r--r--HISTORY26
-rw-r--r--Makefile63
-rw-r--r--README17
-rw-r--r--eepg.c908
-rw-r--r--eepg.h68
-rw-r--r--eit2.c43
-rw-r--r--eit2.h35
-rw-r--r--epghandler.c147
-rw-r--r--epghandler.h17
-rw-r--r--equivhandler.c127
-rw-r--r--extra/en-themes/mhw1_fr.tr81
-rw-r--r--extra/en-themes/mhw2_es.tr103
-rw-r--r--extra/en-themes/sky_it.themes256
-rw-r--r--po/mk_MK.po77
-rw-r--r--setupeepg.c3
-rw-r--r--setupeepg.h2
-rw-r--r--util.c203
-rw-r--r--util.h35
18 files changed, 1671 insertions, 540 deletions
diff --git a/HISTORY b/HISTORY
index f3ccd4d..e28cdd2 100644
--- a/HISTORY
+++ b/HISTORY
@@ -7,16 +7,16 @@ Release 0.0.6pre:
- Fixed charset
- Added viasat support
- Removed include si.c
-- Changed docodeText2 to use code from vdr which also handles charset override
-- Removed some gotos
+- Changed docodeText2 to use code from VDR which also handles charset override
+- Removed some GOTOs
- Removed some code duplication
-- Removed some todos
+- Removed some TODOs
- moved Premiere code in separate method
-- Added setup option to display message after finish of writing epg
+- Added setup option to display message after finish of writing EPG
- Added Dish Network and Bell ExpressVU support, thanks to the VDR patch, Mrgandalf and VDR User
- Applied patch to Load Huffman dictionaries only on first use, thanks to Torsten Lang
- Fixed update of equivalents for Freesat
-- Add category and genere to the description usable with epgsearch
+- Add category and genre to the description usable with epgsearch
- Added EpgHandler for manipulation of the EPG for VDR > 1.7.26
- Try to discard very long events that override more than one existing event
- Equivalents stored in map for all equivalents for better handling
@@ -28,7 +28,21 @@ Release 0.0.6pre:
- Move cEIT2 in a separate file and try to use it in epghandler also
- Drop unmanaged NOEPG support, there is a separate plugin for that
- Drop unmanaged Disable Double EPG entry. EEPG tries to handle this anyway
-- Aditional fixes logged at http://projects.vdr-developer.org/git/vdr-plugin-eepg.git/
+- Added Short Text to events extracted from the extended description for MHW2 and Sky
+- Added option to setup not to set Category and Genre to empty short texts
+- Added po Translation support
+- added Macedonian translation
+- Added functionality to try to fix the charset for some known providers that incorrectly announce charset.
+ This has to be enabled from setup menu.
+- Updated handling of duplicate events, and implemented for equivalent channels.
+- Dropping already expired events without adding them to the schedule, this reduces cleanups
+- Changed the logic of summary handling for SKY so that no SummaryAvailable bit is required, since it can not be located from the stream
+- Reformatted MHW1 themes
+- Added some new/missing SKY themes
+- Added ability to translate themes. See README/Examples
+- Added support for Freeview HD (DVB-T)
+
+- Additional fixes logged at http://projects.vdr-developer.org/git/vdr-plugin-eepg.git/
Release 0.0.5:
-changed TableId's so that Now/Next overwrites Nagra which overwrites MHW
diff --git a/Makefile b/Makefile
index c7b93d0..64ebe01 100644
--- a/Makefile
+++ b/Makefile
@@ -24,9 +24,22 @@
#
PLUGIN = eepg
+# Output control
+ifdef VERBOSE
+Q =
+else
+Q = @
+endif
+export Q
+
### The version number of this plugin (taken from the main source file):
-VERSION = $(shell grep 'static const char \*VERSION *=' $(PLUGIN).c | awk '{ print $$6 }' | sed -e 's/[";]//g')
+RELEASE := $(shell grep 'static const char \*VERSION *=' $(PLUGIN).c | awk '{ print $$6 }' | sed -e 's/[";]//g')
+SUBREL := $(shell if test -d .git; then \
+ echo -n "-git-"; (git rev-parse --short HEAD 2>/dev/null || echo -n "Unknown") | sed -e 's/ .*//'; \
+ fi)
+VERSION := $(RELEASE)$(SUBREL)
+#VERSION = $(shell grep 'static const char \*VERSION *=' $(PLUGIN).c | awk '{ print $$6 }' | sed -e 's/[";]//g')
### The directory environment:
@@ -47,6 +60,28 @@ export CXXFLAGS = $(call PKGCFG,cxxflags)
APIVERSION = $(call PKGCFG,apiversion)
+# backward compatibility with VDR version < 1.7.34
+API1733 := $(shell if [ "$(APIVERSION)" \< "1.7.34" ]; then echo true; fi; )
+
+ifdef API1733
+
+VDRSRC = $(VDRDIR)
+ifeq ($(strip $(VDRSRC)),)
+VDRSRC := ../../..
+endif
+LIBDIR = $(VDRSRC)/PLUGINS/lib
+
+ifndef NOCONFIG
+CXXFLAGS = $(call PKGCFG,cflags)
+CXXFLAGS += -fPIC
+else
+-include $(VDRSRC)/Make.global
+-include $(VDRSRC)/Make.config
+endif
+
+export CXXFLAGS
+endif
+
### Allow user defined options to overwrite defaults:
-include $(PLGCFG)
@@ -63,7 +98,9 @@ SOFILE = libvdr-$(PLUGIN).so
### Includes and Defines (add further entries here):
+ifdef API1733
INCLUDES += -I$(VDRDIR)/include
+endif
DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
@@ -73,12 +110,17 @@ OBJS = $(PLUGIN).o dish.o epghandler.o setupeepg.o equivhandler.o util.o eit2.o
### The main target:
-all: $(SOFILE)
+ifdef API1733
+all: libvdr-$(PLUGIN).so i18n
+else
+all: $(SOFILE) i18n
+endif
### Implicit rules:
%.o: %.c
- $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
+ @echo CC $@
+ $(Q)$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
### Dependencies:
@@ -98,17 +140,21 @@ I18Nmsgs = $(addprefix $(DESTDIR)$(LOCDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLU
I18Npot = $(PODIR)/$(PLUGIN).pot
%.mo: %.po
- msgfmt -c -o $@ $<
+ @echo MO $@
+ $(Q)msgfmt -c -o $@ $<
$(I18Npot): $(wildcard *.c)
- xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=vdr-$(PLUGIN) --package-version=$(VERSION) --msgid-bugs-address='<see README>' -o $@ `ls $^`
+ @echo GT $@
+ $(Q)xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=vdr-$(PLUGIN) --package-version=$(VERSION) --msgid-bugs-address='<see README>' -o $@ `ls $^`
%.po: $(I18Npot)
- msgmerge -U --no-wrap --no-location --backup=none -q -N $@ $<
+ @echo PO $@
+ $(Q)msgmerge -U --no-wrap --no-location --backup=none -q -N $@ $<
@touch $@
$(I18Nmsgs): $(DESTDIR)$(LOCDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo
- install -D -m644 $< $@
+ @echo IN $@
+ $(Q)install -D -m644 $< $@
.PHONY: i18n
i18n: $(I18Nmo) $(I18Npot)
@@ -118,7 +164,8 @@ install-i18n: $(I18Nmsgs)
### Targets:
$(SOFILE): $(OBJS)
- $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@
+ @echo LD $@
+ $(Q)$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@
install-lib: $(SOFILE)
install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION)
diff --git a/README b/README
index 6dee8d5..4e9dd9d 100644
--- a/README
+++ b/README
@@ -32,6 +32,7 @@ Currently the following EEPG formats are supported:
* Sky Italy
* Sky UK
* Freesat
+* Freeview
* Premiere
* NagraGuide (CanaalDigitaalNL, only in test)
* NA Dish and BEV
@@ -102,6 +103,17 @@ In addition there are two switches in the plugin setup menu to control inclusion
of order and parental rating information into the event description.
The plugin setup menu is only for Premiere protocol!
+Optionally EEPG can try to fix the charset of providers that send the EPG data with no
+or incorrect Charset. In order for EEPG to try to fix the charset the option must be
+selected from the menu.
+This is a workaround fix which does double conversion and depends on
+already know data for providers that send incorrect charset.
+The real solution is for Providers to follow the standards and not to do this in the first place.
+
+The themes of the EPG events can be translated. For MHW a translation file is used, and for OTV the
+theme file should be translated.
+See example english translation files in: extra/en-themes/*.*
+This files should be placed in eepg plugin config directory.
THANKS
This code is based on:
@@ -114,6 +126,8 @@ This code is based on:
Thanks to mrgandalf, and the others who helped map NA eit.
Thanks to VDR User for testing and providing makequiv.sh script for S72.7W channels.
Thanks to cheesemonster for providing a patch to fix multipe device problems
+Thanks to Tony Houghton and Stuart Morris for testing Freeview HD
+Thanks to Matthias Feistel for the wrong lock sequence fix
We wish to thank all authors for the great work they have been doing, decoding
this EEPG data; this plugin tries to combine the best of all worlds.
@@ -130,7 +144,4 @@ information.
KNOWN BUGS
-Equivalents file is not used for Premiere.
--On Sky Italy and Sky UK, a lot of "summaries not found" are reported. This is
- because it is not (yet) known where the "summary available" flag is coded in the
- OpenTV protocol used, so all titles are assumed to have a summary available.
diff --git a/eepg.c b/eepg.c
index 8573446..b319a46 100644
--- a/eepg.c
+++ b/eepg.c
@@ -49,7 +49,9 @@
#include <map>
#include <string>
+#include <limits>
#include <stdarg.h>
+#include <dirent.h>
#if defined(APIVERSNUM) && APIVERSNUM < 10401
@@ -111,7 +113,13 @@ public:
cMenuSetupPremiereEpg::cMenuSetupPremiereEpg (void)
{
data = cSetupEEPG::getInstance();
- SetSection (tr ("PremiereEPG"));
+ cOsdItem *item = new cOsdItem(tr ("PremiereEPG"));
+
+ if (item) {
+ item->SetSelectable(false);
+ Add(item);
+ }
+// AddCategory (tr ("PremiereEPG"));
optDisp[0] = tr ("off");
for (unsigned int i = 1; i < NUM_PATS; i++) {
snprintf (buff[i], sizeof (buff[i]), optPats[i], "Event", 1);
@@ -121,7 +129,15 @@ cMenuSetupPremiereEpg::cMenuSetupPremiereEpg (void)
Add (new cMenuEditBoolItem (tr ("Show order information"), &data->OrderInfo));
Add (new cMenuEditBoolItem (tr ("Show rating information"), &data->RatingInfo));
Add (new cMenuEditBoolItem (tr ("Fix EPG data"), &data->FixEpg));
+ item = new cOsdItem(tr ("General"));
+ if (item) {
+ item->SetSelectable(false);
+ Add(item);
+ }
+// AddCategory (tr ("General"));
Add (new cMenuEditBoolItem (tr ("Display summary message"), &data->DisplayMessage));
+ Add (new cMenuEditBoolItem (tr ("Replace empty Short Text with Category - Genre"), &data->ReplaceEmptyShText));
+ Add (new cMenuEditBoolItem (tr ("Try to fix CharSet for events"), &data->FixCharset));
#ifdef DEBUG
Add (new cMenuEditIntItem (tr ("Level of logging verbosity"), &data->LogLevel, 0, 5));
Add (new cMenuEditBoolItem (tr ("Process EIT info with EEPG"), &data->ProcessEIT));
@@ -136,6 +152,8 @@ void cMenuSetupPremiereEpg::Store (void)
SetupStore ("RatingInfo", SetupPE->RatingInfo);
SetupStore ("FixEpg", SetupPE->FixEpg);
SetupStore ("DisplayMessage", SetupPE->DisplayMessage);
+ SetupStore ("ReplaceEmptyShText", SetupPE->ReplaceEmptyShText);
+ SetupStore ("FixCharset", SetupPE->FixCharset);
#ifdef DEBUG
SetupStore ("LogLevel", SetupPE->LogLevel);
SetupStore ("ProcessEIT", SetupPE->ProcessEIT);
@@ -205,7 +223,7 @@ protected:
virtual bool GetThemesSKYBOX (void);
virtual int GetTitlesSKYBOX (const u_char * Data, int Length);
virtual int GetSummariesSKYBOX (const u_char * Data, int Length);
- virtual int GetChannelsMHW (const u_char * Data, int Length, int MHW); //TODO replace MHW by Format?
+ virtual int GetChannelsMHW (const u_char * Data, int Length);
virtual int GetThemesMHW1 (const u_char * Data, int Length);
virtual int GetNagra (const u_char * Data, int Length);
virtual void ProcessNagra (void);
@@ -224,7 +242,7 @@ protected:
//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);
+ unsigned short int TableId, unsigned short int Version, char Rating = 0x00, unsigned char ShortTextLenght = 0);
virtual void LoadIntoSchedule (void);
//virtual void LoadEquivalentChannels (void);
@@ -275,7 +293,7 @@ void cFilterEEPG::SetStatus (bool On)
void cFilterEEPG::NextPmt (void)
{
- Del (pmtpid, 0x02);
+ Del (pmtpid, SI::TableIdPMT);
pmtpid = 0;
pmtidx++;
LogE(3, prep("PMT next\n"));
@@ -306,23 +324,6 @@ void syslog_with_tid (int priority, const char *format, ...) __attribute__ ((for
#define isyslog(a...) fprintf(stderr,a)
#endif
-
-
-//struct hufftab {
-// unsigned int value;
-// short bits;
-// char next;
-//};
-//
-//#define START '\0'
-//#define STOP '\0'
-//#define ESCAPE '\1'
-
-
-//int freesat_decode_error = 0; /* If set an error has occurred during decoding */
-
-//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
@@ -419,7 +420,7 @@ static bool load_freesat_file (int tableid, const char *filename)
return true;
}
-/** \brief Load an individual freesat data file
+/** \brief Load an individual sky data file
*
* \param filename - Filename to load
* \return Success of operation
@@ -553,6 +554,75 @@ bool cFilterEEPG::load_sky_file (const char *filename)
return true;
}
+#define THEME_TR ".tr"
+
+void load_theme_dictionaries (void)
+{
+ char Buffer[1024];
+ char *Line;
+ FILE *File;
+
+ DIR *dp = opendir(cSetupEEPG::getInstance()->getConfDir());
+ struct dirent *dirp;
+ if(!dp) {
+ LogE (0, prep("Can't read configuration folder '%s'"), cSetupEEPG::getInstance()->getConfDir());
+ return ;
+ }
+
+ if (tableDict.size() > 0)
+ tableDict.clear();
+
+
+ while ((dirp = readdir(dp)) != NULL) {
+
+ string fname = dirp->d_name; // filename
+ if (dirp->d_type == DT_DIR || // if entry is a directory
+ fname.find(THEME_TR, (fname.length() - strlen(THEME_TR))) == string::npos){
+ continue;
+ }
+
+ fname = string(cSetupEEPG::getInstance()->getConfDir()) + "/" + fname;
+
+ //Test if file is changed and reload
+ struct stat st;
+ if (stat(fname.c_str(), &st)) {
+ LogE(0, prep("Error obtaining stats for '%s' "), fname.c_str());
+ continue;
+ }
+
+ File = fopen (fname.c_str(), "r");
+ if (!File) continue;
+
+ memset (Buffer, 0, sizeof (Buffer));
+ char origThemeName[256];
+ char transThemeName[256];
+ while ((Line = fgets (Buffer, sizeof (Buffer), File)) != NULL) {
+ Line = compactspace (skipspace (stripspace (Line)));
+ //Skip empty and commented lines
+ if (isempty (Line) || Line[0] == '#' || Line[0] == ';') continue;
+ if (sscanf (Line, "%[^=]=%[^\n]\n", origThemeName, transThemeName) == 2) {
+
+ string origTh(compactspace (skipspace (stripspace (origThemeName))));
+ string transTh(compactspace (skipspace (stripspace (transThemeName))));
+ if (!tableDict.count(origTh) && !transTh.empty()) {
+ tableDict.insert(pair<string,string>(string(origThemeName),string(transThemeName)));
+ LogD(4, prep("Original '%s' translation to '%s'."), origTh.c_str(), transTh.c_str());
+ }
+ } //if scanf
+ } //while
+ fclose (File);
+ LogD(3, prep("Loaded %i translations from %s."), tableDict.size(), fname.c_str());
+ }
+ closedir(dp);
+
+ LogD(2, prep("Loaded %i translations."), tableDict.size());
+ LogD(2, prep("Original <-> Translation"));
+ map<string,string>::iterator it;
+ for ( it=tableDict.begin() ; it != tableDict.end(); it++ )
+ LogD(2, prep("%s <-> %s"), (*it).first.c_str(), it->second.c_str());
+
+}
+
/** \brief Decode an EPG string as necessary
*
* \param src - Possibly encoded string
@@ -741,11 +811,6 @@ nextloop1:
return p;
}
-//here all declarations for global variables over all devices
-
-//char *ConfDir;
-
-//unsigned char DecodeErrorText[4096]; //TODO only used for debugging?
bool cFilterEEPG::GetThemesSKYBOX (void) //TODO can't we read this from the DVB stream?
{
@@ -753,10 +818,16 @@ bool cFilterEEPG::GetThemesSKYBOX (void) //TODO can't we read this from the DVB
FILE *FileThemes;
char *Line;
char Buffer[256];
- if (Format == SKY_IT)
+ const char **SkyThemes;
+ bool updateFile = false;
+ if (Format == SKY_IT) {
FileName += "/sky_it.themes";
- else if (Format == SKY_UK)
+ SkyThemes = SkyItThemes;
+ }
+ else if (Format == SKY_UK) {
FileName += "/sky_uk.themes";
+ SkyThemes = SkyUkThemes;
+ }
else {
LogE (0, prep("Error, wrong format detected in GetThemesSKYBOX. Format = %i."), Format);
return false;
@@ -767,26 +838,49 @@ bool cFilterEEPG::GetThemesSKYBOX (void) //TODO can't we read this from the DVB
LogE (0, prep("Error opening file '%s'. %s"), FileName.c_str(), strerror (errno));
return false;
} else {
- //int id = 0;
+ int id = 0;
nThemes = 0;
- char string1[256];
- char string2[256];
- //sTheme *T;
+ char thId[256];
+ char theme[256];
+
while ((Line = fgets (Buffer, sizeof (Buffer), FileThemes)) != NULL) {
- memset (string1, 0, sizeof (string1));
- memset (string2, 0, sizeof (string2));
+ memset (thId, 0, sizeof (thId));
+ memset (theme, 0, sizeof (theme));
if (!isempty (Line)) {
- //T = &Themes[nThemes];
- if (sscanf (Line, "%[^=] =%[^\n] ", string1, string2) == 2) {
- snprintf ((char *) Themes[nThemes], 255, "%s", string2);
+ if (sscanf (Line, "%[^=] =%[^\n] ", thId, theme) == 2 && !isempty (theme)) {
+ snprintf ((char *) Themes[id], 255, "%s", theme);
+ nThemes++;
} else {
- Themes[nThemes][0] = '\0';
+ if (SkyThemes[id]) {
+ updateFile = true;
+ snprintf ((char *) Themes[id], 255, "%s", SkyThemes[id]);
+ LogD (1, prep("Theme '%s' missing in theme file '%s'"), SkyThemes[id], FileName.c_str());
+ } else
+ Themes[id][0] = '\0';
}
- //id ++;
- nThemes++;
+ id ++;
}
}
fclose (FileThemes);
+
+ if (updateFile) {
+ FileThemes = fopen (FileName.c_str(), "w");
+ if (FileThemes == NULL) {
+ LogE (0, prep("Error re-creating file '%s', %s"), FileName.c_str(), strerror (errno));
+ } else {
+ for (int i = 0; i < 256; i++) {
+ if (Themes[i]) {
+ fprintf (FileThemes, "0x%02x=%s\n", i, (char *) Themes[i]);
+ }
+ else {
+ fprintf (FileThemes, "0x%02x=\n", i);
+ }
+ }
+
+ LogI (0, prep("Success updating file '%s'"), FileName.c_str());
+ fclose (FileThemes);
+ }
+ }
}
return true;
}
@@ -839,24 +933,25 @@ bool cFilterEEPG::InitDictionary (void)
return true;
}
-
/**
* \brief Get MHW channels
*
* \return 0 = fatal error, code 1 = success, code 2 = last item processed
*/
-int cFilterEEPG::GetChannelsMHW (const u_char * Data, int Length, int MHW)
+int cFilterEEPG::GetChannelsMHW (const u_char * Data, int Length)
{
- if ((MHW == 1) || (nChannels == 0)) { //prevents MHW2 from reading channels twice while waiting for themes on same filter
+ if (Format != MHW1 && Format != MHW2) return 0;
+
+ if ((Format == MHW1) || (nChannels == 0)) { //prevents MHW2 from reading channels twice while waiting for themes on same filter
sChannelMHW1 *Channel;
int Size, Off;
Size = sizeof (sChannelMHW1);
Off = 4;
- if (MHW == 1) {
+ if (Format == MHW1) {
//Channel = (sChannelMHW1 *) (Data + 4);
nChannels = (Length - Off) / sizeof (sChannelMHW1);
}
- if (MHW == 2) {
+ if (Format == MHW2) {
if (Length > 120)
nChannels = Data[120];
else {
@@ -882,13 +977,14 @@ int cFilterEEPG::GetChannelsMHW (const u_char * Data, int Length, int MHW)
LogI(1, "|------|-%-26.26s-|-%-22.22s-|-----|-%-8.8s-|\n", "------------------------------",
"-----------------------------", "--------------------");
int pName = ((nChannels * 8) + 121); //TODO double ...
+ LogD(1, prep("Length:%d pName:%d diff:%d"), Length, pName, Length - pName);
for (int i = 0; i < nChannels; i++) {
Channel = (sChannelMHW1 *) (Data + Off);
sChannel *C = &sChannels[i];
C->ChannelId = i;
ChannelSeq[C->ChannelId] = i; //fill lookup table to go from channel-id to sequence nr in table
C->SkyNumber = 0;
- if (MHW == 1)
+ if (Format == MHW1)
memcpy (C->Name, &Channel->Name, 16); //MHW1
else { //MHW2
int lenName = Data[pName] & 0x0f;
@@ -905,7 +1001,7 @@ int cFilterEEPG::GetChannelsMHW (const u_char * Data, int Length, int MHW)
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);
+ const cChannel *VC = GetChannelByID(channelID, true);
bool IsFound = (VC);
if(IsFound) {
C->Src = VC->Source();
@@ -949,13 +1045,38 @@ int cFilterEEPG::GetThemesMHW1 (const u_char * Data, int Length)
const u_char *ThemesIndex = (Data + 3);
for (int i = 0; i < nThemes; i++) {
if (ThemesIndex[ThemeId] == i) {
- Offset = (Offset + 15) & 0xf0; //TODO do not understand this
+ //The index of the Themes in MHW1 is not incremented by 1 but with offset calculated like this
+ Offset = (Offset + 15) & 0xf0;
ThemeId++;
}
memcpy (&Themes[Offset][0], &Theme->Name, 15);
Themes[Offset][15] = '\0'; //trailing null
CleanString (Themes[Offset]);
- LogI(1, prep("%.15s"), Themes[Offset]);
+
+ //reformat themes
+ if (Offset & 0x0f) {
+ char* theme;
+ char* cat;
+ Asprintf (&theme, "%s", Themes[Offset]);
+ Asprintf (&cat, "%s", Themes[Offset& 0xf0]);
+ theme = strreplace(theme,"DOC","DOCUMENTAIRE");
+ theme = strreplace(theme,"DOCUMENTAIRE.","DOCUMENTAIRE");
+ theme = strreplace(theme,"MAG","MAGAZINE");
+ theme = strreplace(theme,"INFO-METEO","INFO/METEO");
+ //Remove category from genre. TODO Maybe they should be separated in the future
+ theme = strreplace(theme,cat,"");
+ theme = skipspace(theme);
+ if (theme[0] == '-') {
+ memmove(theme, theme+1, strlen(theme));
+ theme = skipspace(theme);
+ }
+ char* buf;
+ Asprintf(&buf,"%s - %s",cat,theme);
+ memcpy(Themes[Offset],buf,strlen(buf)+1);
+ }
+
+ LogI(1, prep("%-33.33s|Offset:0x%02x"), Themes[Offset],Offset);
+
Offset++;
Theme++;
}
@@ -1017,7 +1138,7 @@ int cFilterEEPG::GetThemesMHW2 (const u_char * Data, int Length)
//memcpy (&Themes[pThemeId][lenThemeName + 1], &Data[pSubThemeName], lenSubThemeName);
}
CleanString (Themes[pThemeId]);
- LogI(1, prep("%.*s"), lenThemeName + 1 + lenSubThemeName, Themes[pThemeId]);
+ LogI(1, prep("%.40s|id:%d"), Themes[pThemeId],pThemeId);
//isyslog ("%.15s", (lThemes + pThemeId)->Name);
nThemes++;
if (nThemes > MAX_THEMES) {
@@ -1177,42 +1298,6 @@ char *cFilterEEPG::GetSummaryTextNagra (const u_char * DataStart, long int Offse
return (char *) Text;
}
-/**
- * \brief Prepare to Write to Schedule
- *
- * 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
- *
- * \param C channel to prepare
- * \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]);
-// }
-//}
/**
* \brief write event to schedule
@@ -1220,7 +1305,11 @@ char *cFilterEEPG::GetSummaryTextNagra (const u_char * DataStart, long int Offse
* \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 (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)
+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,
+ unsigned char ShTxtLen)
{
bool WrittenTitle = false;
bool WrittenSummary = false;
@@ -1262,21 +1351,77 @@ void cFilterEEPG::WriteToSchedule (tChannelID channelID, cSchedules* pSchedules,
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) {
+
+ char* tmp = NULL;
+ string shText;
+ if (SummText && ShTxtLen) {
+
+ shText.assign(SummText,ShTxtLen);
+ //LogD(0, prep("DEBUG: Title '%s', Subtitle '%s'"), Text, shText.c_str());
+ string tmpTitle(Text);
+ if (Format == MHW2 && !shText.empty()) {
+ size_t found = tmpTitle.find(" (HD)");
+ if (found != string::npos)
+ tmpTitle.erase(found, 5);
+ //found = shText.compare(0, tmpTitle.size() + 2, string(tmpTitle + ": "));
+ if (shText.compare(0, tmpTitle.size() + 2, string(tmpTitle + ": "))==0)
+ shText.erase(0, tmpTitle.size() + 2);
+
+ //Remove Subtitle from title it is not pretty.
+ //int sumLen = strlen(SummText);
+ //if (sumLen > ShTxtLen)
+ // memmove(SummText,SummText + ShTxtLen + 1, sumLen - ShTxtLen);
+ }
+
+ //Do not use Subtitle if it is substring of Title
+ if (tmpTitle.compare(0, shText.size(), shText) == 0)
+ shText.clear();
+
+ //The subtitle is wrong if contains '.' after possible initial '...'
+ if (Format == SKY_UK && !shText.empty() && shText.find('.',3) != string::npos) {
+ shText.clear();
+ }
+
+#define MAX_USEFUL_EPISODE_LENGTH 40
+ // From VDR FixEPG Bugs
+ // Some channels put a whole lot of information in the ShortText and leave
+ // the Description totally empty. So if the ShortText length exceeds
+ // MAX_USEFUL_EPISODE_LENGTH, let's put this into the Description
+ // instead:
+ if (Format != SKY_IT && Format != MHW2 && !shText.empty() && shText.size() > MAX_USEFUL_EPISODE_LENGTH)
+ shText.clear();
+
+ }
+ if (!shText.empty())
+ Event->SetShortText (shText.c_str());
+ else if (SetupPE->ReplaceEmptyShText) {
+ Asprintf (&tmp, "%s - %d\'", Themes[ThemeId], Duration);
+ Event->SetShortText (tmp);
+ free(tmp);
+ }
+
+ if (SummText) {
WrittenSummary = true;
CleanString ((uchar *) SummText);
+ //Fix MHW1 formating
+ if (Format == MHW1) {
+ char * pch;
+ pch=strchr(SummText,'s');
+ while (pch!=NULL) {
+ if (*(pch-1) != ' ' && *(pch-1) != '\n')
+ *pch = ' ';
+ pch=strchr(pch+1,'s');
+ }
+ }
+
//Add themes and categories epgsearch style
+ //TODO DPE move this
char *theme;
Asprintf (&theme, "%s", Themes[ThemeId]);
if (theme && 0 != strcmp(theme,"")) {
@@ -1291,22 +1436,32 @@ void cFilterEEPG::WriteToSchedule (tChannelID channelID, cSchedules* pSchedules,
}else{
category = theme;
}
- string fmt;
- fmt = "%s";
- if (stripspace(category)) {
- fmt += "\nCategory: %s";
- }
- if (genre) {
- fmt += "\nGenre: %s";
+
+ string desc = SummText;
+ if (Format == MHW2 && ShTxtLen) {
+ desc.erase(0, ShTxtLen + 1);
}
- Asprintf (&tmp, fmt.c_str(), SummText, category, stripspace (genre));
+ if (stripspace(category)) desc.append("\n").append(CATEGORY).append(findThemeTr(category));
+ if (stripspace(genre)) desc += '\n' + string(GENRE) + findThemeTr(genre);
+ Event->SetDescription (desc.c_str());
- Event->SetDescription (tmp);
- free(tmp);
free(theme);
- }
- else
- Event->SetDescription (SummText);
+ }
+ else {
+#ifdef DEBUG
+ string desc = SummText;
+ if (ThemeId) {
+ char *theme;
+ Asprintf (&theme, "0x%x", ThemeId);
+ LogD(0, prep("DEBUG: missing theme ID 0x%x title:'%s'"), ThemeId, Event->Title());
+ desc += '\n' + string(GENRE) + theme;
+ free(theme);
+ }
+ Event->SetDescription (desc.c_str());
+#else
+ Event->SetDescription (SummText);
+#endif
+ }
}
if (ps && newEvent)
ps->AddEvent (newEvent);
@@ -1360,8 +1515,12 @@ void cFilterEEPG::GetTitlesNagra (const u_char * Data, int Length, unsigned shor
unsigned short int CurrentYear = tmCurrent->tm_year;
unsigned short int CurrentMonth = tmCurrent->tm_mon;
//esyslog("EEPGDEBUG: CurrentMonthday=%i, TableIdExtension:%04x, MonthdayTitles=%i.",CurrentMonthday,TableIdExtension, MonthdayTitles);
+#if APIVERSNUM >= 20300
+ LOCK_SCHEDULES_WRITE;
+#else
cSchedulesLock SchedulesLock (true);
- cSchedules *s = (cSchedules *) cSchedules::Schedules (SchedulesLock);
+ cSchedules *Schedules = (cSchedules *) cSchedules::Schedules (SchedulesLock);
+#endif
do { //process each block of titles
sTitleBlockNagraGuide *TB = (sTitleBlockNagraGuide *) p;
int ChannelId = HILO16 (TB->ChannelId);
@@ -1380,7 +1539,7 @@ void cFilterEEPG::GetTitlesNagra (const u_char * Data, int Length, unsigned shor
sChannel *C = &sChannels[ChannelSeq[ChannelId]]; //find channel
//cSchedule *ps = NULL;//[MAX_EQUIVALENCES];
- //PrepareToWriteToSchedule (C, s, ps);
+ //PrepareToWriteToSchedule (C, Schedules, ps);
for (int i = 0; i < NumberOfTitles; i++) { //process each title within block
sTitleNagraGuide *Title = (sTitleNagraGuide *) p;
@@ -1431,7 +1590,7 @@ 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 (tChannelID (C->Src, C->Nid, C->Tid, C->Sid), s, EventId, StartTime, Title->Duration, Text, SummText,
+ WriteToSchedule (tChannelID (C->Src, C->Nid, C->Tid, C->Sid), Schedules, EventId, StartTime, Title->Duration, Text, SummText,
Title->ThemeId, NAGRA_TABLE_ID, Version);
if (Text != NULL)
@@ -1470,7 +1629,7 @@ void cFilterEEPG::GetTitlesNagra (const u_char * Data, int Length, unsigned shor
} //end for titles
//FinishWriteToSchedule (C, s, ps);
- sortSchedules(s, tChannelID (C->Src, C->Nid, C->Tid, C->Sid));
+ sortSchedules(Schedules, tChannelID (C->Src, C->Nid, C->Tid, C->Sid));
p = next_p;
} while (p < DataEnd); //end of TitleBlock
}
@@ -1593,7 +1752,7 @@ int cFilterEEPG::GetChannelsNagra (const u_char * Data, int Length)
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);
+ const cChannel *VC = GetChannelByID(channelID, true);
bool IsFound = (VC);
if(IsFound) {
strncpy((char*)(C->Name), VC->Name (), 64);
@@ -1882,29 +2041,7 @@ int cFilterEEPG::GetTitlesMHW2 (const u_char * Data, int Length)
if (Length > 18) {
int Pos = 18;
int Len = 0;
- /*bool Check = false;
- while (Pos < Length) {
- Check = false;
- Pos += 7;
- if (Pos < Length) {
- Pos += 3;
- if (Pos < Length)
- if (Data[Pos] > 0xc0) {
- Pos += (Data[Pos] - 0xc0);
- Pos += 4;
- if (Pos < Length) {
- if (Data[Pos] == 0xff) {
- Pos += 1;
- Check = true;
- }
- }
- }
- }
- if (Check == false){
- isyslog ("EEPGDebug: Check==false");
- return 1; // I assume nonfatal error or success
- }
- }*/
+
if (memcmp (InitialTitle, Data, 16) == 0) { //data is the same as initial title
return 2; //last item processed
} else {
@@ -1918,11 +2055,8 @@ int cFilterEEPG::GetTitlesMHW2 (const u_char * Data, int Length)
T->ChannelId = Data[Pos];
Pos+=11;//The date time starts here
//isyslog ("EEPGDebug: ChannelID:%d", T->ChannelId);
- unsigned int MjdTime = (Data[Pos] << 8) | Data[Pos + 1];
- T->MjdTime = 0; //not used for matching MHW2
- T->StartTime = ((MjdTime - 40587) * 86400)
- + (((((Data[Pos + 2] & 0xf0) >> 4) * 10) + (Data[Pos + 2] & 0x0f)) * 3600)
- + (((((Data[Pos + 3] & 0xf0) >> 4) * 10) + (Data[Pos + 3] & 0x0f)) * 60);
+ T->MjdTime = 0; //(Data[Pos] << 8) | Data[Pos + 1] not used for matching MHW2
+ T->StartTime = MjdToEpochTime(Data[Pos], Data[Pos + 1], Data[Pos + 2], Data[Pos + 3]);
T->Duration = (((Data[Pos + 5] << 8) | Data[Pos + 6]) >> 4) * 60;
Len = Data[Pos + 7] & 0x3f;
//isyslog ("EEPGDebug: Len:%d", Len);
@@ -1979,7 +2113,7 @@ int cFilterEEPG::GetSummariesMHW1 (const u_char * Data, int Length)
LogE(0, prep("Summaries memory allocation error."));
return 0;
}
- Text[SummaryLength+1] = '\0'; //end string with NULL character
+ //Text[SummaryLength+1] = '\0'; //end string with NULL character
//memcpy (Text, &Data[SummaryOffset], SummaryLength);
decodeText2(&Data[SummaryOffset], SummaryLength, (char*)Text, 2*SummaryLength + 1);
// CleanString (Text);
@@ -1992,7 +2126,10 @@ int cFilterEEPG::GetSummariesMHW1 (const u_char * Data, int Length)
Summaries[nSummaries] = S;
S->NumReplays = Summary->NumReplays;
S->EventId = HILO32 (Summary->ProgramId);
+// unsigned short SectionLength = ((Summary->SectionLengthHigh & 0x0f) << 8) | Summary->SectionLengthLow;
+// Asprintf((char **)&Text, "%s \n\n SecLength:%d SLHigh:%d SLLow:%d", Text, SectionLength, Summary->SectionLengthHigh, Summary->SectionLengthLow);
S->Text = Text;
+ S->ShortTextLength = 0; //TODO DPE find for MHW1
int i = 0;
do {
S->Replays[i].MjdTime = 0; //only used for SKY
@@ -2013,11 +2150,7 @@ int cFilterEEPG::GetSummariesMHW1 (const u_char * Data, int Length)
S->EventId, S->Replays[i].ChannelId,
sChannels[ChannelSeq[S->Replays[i].ChannelId]].Name, Hour, Minute, Sec);
- S->Replays[i].StartTime = MjdToEpochTime (Date) + (((((Hour & 0xf0) >> 4) * 10) + (Hour & 0x0f)) * 3600)
- + (((((Minute & 0xf0) >> 4) * 10) + (Minute & 0x0f)) * 60)
- + ((((Sec & 0xf0) >> 4) * 10) + (Sec & 0x0f));
-// summary -> time[i] = ProviderLocalTime2UTC (summary -> time[i]);
- S->Replays[i].StartTime = LocalTime2UTC (S->Replays[i].StartTime);
+ S->Replays[i].StartTime = LocalTime2UTC (MjdToEpochTime (Date_hi, Date_lo, Hour, Minute, Sec));
//}
i++;
} while (i < Summary->NumReplays);
@@ -2111,6 +2244,9 @@ int cFilterEEPG::GetSummariesMHW2 (const u_char * Data, int Length)
//S->Text[SummaryLength] = '\0'; //end string with NULL character
decodeText2(tmp,SummaryLength,(char*)S->Text,2 * SummaryLength + 1);
CleanString (S->Text);
+ char * delim = strchr ( (char *)S->Text, '\n' );
+ S->ShortTextLength = delim == NULL ? 0 : delim - (char *)S->Text;
+
LogI(3, prep("EventId %08x Summnr %d:%.30s."), S->EventId, nSummaries, S->Text);
nSummaries++;
} else {
@@ -2157,67 +2293,64 @@ int cFilterEEPG::GetChannelsSKYBOX (const u_char * Data, int Length)
while (TransportDescriptorsLength > 0) {
unsigned char DescriptorTag = Data[p2];
int DescriptorLength = Data[p2 + 1];
- int p3 = (p2 + 2);
+ int p3 = (p2 + 4);
p2 += (DescriptorLength + 2);
TransportDescriptorsLength -= (DescriptorLength + 2);
- switch (DescriptorTag) { //TODO switch with only 1 case??? replace this by template
- case 0xb1:
- p3 += 2;
- DescriptorLength -= 2;
- while (DescriptorLength > 0) {
- // 0x01 = Video Channel
- // 0x02 = Audio Channel
- // 0x05 = Other Channel
- //if( Data[p3+2] == 0x01 || Data[p3+2] == 0x02 || Data[p3+2] == 0x05 )
- //{
- unsigned short int Sid = (Data[p3] << 8) | Data[p3 + 1];
- unsigned short int ChannelId = (Data[p3 + 3] << 8) | Data[p3 + 4];
- unsigned short int SkyNumber = (Data[p3 + 5] << 8) | Data[p3 + 6];
- if (SkyNumber > 100 && SkyNumber < 1000) {
- if (ChannelId > 0) {
- sChannel *C;
- 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 = 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, C->Nid, C->Tid, C->Sid);
- cChannel *VC = Channels.GetByChannelID (channelID, true);
- bool IsFound = (VC);
- if (IsFound)
- strncpy ((char *) C->Name, VC->Name (), 64);
- else
- C->Name[0] = '\0'; //empty string
-
- LogI(1, "|% 5d | %-26.26s | %-22.22s | %-3.3s | % 6d |\n", C->ChannelId
- , *channelID.ToString(), C->Name, IsFound ? "YES" : "NO", C->SkyNumber);
-
- ChannelSeq[C->ChannelId] = nChannels; //fill lookup table to go from channel-id to sequence nr in table
- nChannels++;
- if (nChannels >= MAX_CHANNELS) {
- LogE(0, prep("Error, %i channels found more than %i"), nChannels, MAX_CHANNELS);
- return 0;
- }
+ if (DescriptorTag != 0xB1)
+ continue;
+
+ DescriptorLength -= 2;
+ while (DescriptorLength > 0) {
+ // 0x01 = Video Channel
+ // 0x02 = Audio Channel
+ // 0x05 = Other Channel
+ //if( Data[p3+2] == 0x01 || Data[p3+2] == 0x02 || Data[p3+2] == 0x05 )
+ //{
+ unsigned short int Sid = (Data[p3] << 8) | Data[p3 + 1];
+ unsigned short int ChannelId = (Data[p3 + 3] << 8) | Data[p3 + 4];
+ unsigned short int SkyNumber = (Data[p3 + 5] << 8) | Data[p3 + 6];
+ if (SkyNumber > 100 && SkyNumber < 1000) {
+ if (ChannelId > 0) {
+ sChannel *C;
+ 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 = 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, C->Nid, C->Tid, C->Sid);
+ const cChannel *VC = GetChannelByID (channelID, false);
+ bool IsFound = (VC);
+ if (IsFound)
+ strncpy ((char *) C->Name, VC->Name (), 64);
+ else
+ C->Name[0] = '\0'; //empty string
+
+ LogI(1, "|% 5d | %-26.26s | %-22.22s | %-3.3s | % 6d |\n", C->ChannelId
+ , *channelID.ToString(), C->Name, IsFound ? "YES" : "NO", C->SkyNumber);
+
+ ChannelSeq[C->ChannelId] = nChannels; //fill lookup table to go from channel-id to sequence nr in table
+ nChannels++;
+ if (nChannels >= MAX_CHANNELS) {
+ LogE(0, prep("Error, %i channels found more than %i"), nChannels, MAX_CHANNELS);
+ return 0;
}
}
}
- p3 += 9;
- DescriptorLength -= 9;
}
- break;
- default:
- break;
- } //switch descriptortag
+ p3 += 9;
+ DescriptorLength -= 9;
+ }
}
} //while
return 1;
} //else part of memcmp
}
+
/**
* \brief Get SKYBOX Titles
*
@@ -2239,7 +2372,7 @@ int cFilterEEPG::GetTitlesSKYBOX (const u_char * Data, int Length)
if (nTitles == 0)
memcpy (InitialTitle, Data, 20); //copy data into initial title
ChannelId = (Data[3] << 8) | Data[4];
- MjdTime = ((Data[8] << 8) | Data[9]);
+ MjdTime = (Data[8] << 8) | Data[9];
if (ChannelId > 0) {
if (MjdTime > 0) {
p = 10;
@@ -2261,12 +2394,12 @@ int cFilterEEPG::GetTitlesSKYBOX (const u_char * Data, int Length)
}
p += 4;
Len2 = Data[p + 1] - 7;
- T->StartTime = ((MjdTime - 40587) * 86400) + ((Data[p + 2] << 9) | (Data[p + 3] << 1));
+ T->StartTime = MjdToEpochTime(MjdTime) + ((Data[p + 2] << 9) | (Data[p + 3] << 1));
T->Duration = ((Data[p + 4] << 9) | (Data[p + 5] << 1));
T->ThemeId = Data[p + 6];
T->TableId = DEFAULT_TABLE_ID; //TODO locate the actual table id
//TODO Data[p + 7] is Quality value add it to description
- //int quality = Data[p + 7];
+ T->Quality = Data[p + 7];
switch (Data[p + 8] & 0x0F) {
case 0x01:
T->Rating = 0x00; //"U"
@@ -2287,9 +2420,9 @@ int cFilterEEPG::GetTitlesSKYBOX (const u_char * Data, int Length)
T->Rating = 0x00; //"-"
break;
}
- T->Unknown1 = Data[p + 4 - 13]; //FIXME
- T->Unknown2 = Data[p + 4 - 12]; //FIXME
- T->Unknown3 = Data[p + 4 - 11]; //FIXME
+ T->Unknown1 = Data[5]; //Bound to Channel/Date
+ T->Unknown2 = Data[6]; //Bound to Channel/Date
+ T->Unknown3 = Data[7]; //Bound to Channel/Date
unsigned char tmp[4096]; //TODO smarter
Len2 = sky_huffman_decode (&Data[p + 9], Len2, tmp);
if (Len2 == 0) {
@@ -2306,8 +2439,8 @@ int cFilterEEPG::GetTitlesSKYBOX (const u_char * Data, int Length)
CleanString (T->Text);
T->SummaryAvailable = 1; //TODO I assume this is true?
- LogI(3, prep("EventId %08x Titlenr %d,Unknown1:%x,Unknown2:%x,Un3:%x,Name:%s."),
- T->EventId, nTitles, T->Unknown1, T->Unknown2, T->Unknown3, T->Text);
+ LogI(3, prep("EventId %08x Titlenr %d,Un1:%x,Un2:%x,Un3:%x,Quality:%x,Name:%s."),
+ T->EventId, nTitles, T->Unknown1, T->Unknown2, T->Unknown3, T->Quality, T->Text);
p += Len1;
nTitles++;
@@ -2334,6 +2467,7 @@ int cFilterEEPG::GetSummariesSKYBOX (const u_char * Data, int Length)
unsigned short int MjdTime;
int Len1;
int Len2;
+ const char* STxtDelim = Format == SKY_UK?": ":" - ";
if (Length < 20) {
return 1; //non fatal error I assume
@@ -2357,6 +2491,7 @@ int cFilterEEPG::GetSummariesSKYBOX (const u_char * Data, int Length)
S->Replays[0].MjdTime = MjdTime;
S->NumReplays = 0; //not used
S->EventId = (Data[p] << 8) | Data[p + 1];
+ S->ShortTextLength = 0;
Len1 = ((Data[p + 2] & 0x0f) << 8) | Data[p + 3];
if (Data[p + 4] != 0xb9) {
LogD(5, prep("Data error signature for title - Data[p + 4] != 0xb5"));
@@ -2382,7 +2517,18 @@ int cFilterEEPG::GetSummariesSKYBOX (const u_char * Data, int Length)
memcpy (S->Text, tmp, Len2);
S->Text[Len2] = '\0'; //end string with NULL character
CleanString (S->Text);
- LogI(3, prep("EventId %08x Summnr %d:%.30s."), S->EventId, nSummaries, S->Text);
+ char * delim = strstr ( (char *)S->Text, STxtDelim );
+ //S->ShortTextLength = delim == NULL ? 0 : delim - (char *)S->Text;
+ if (Format == SKY_UK && !delim && strncmp((char *)S->Text,"..",2) == 0) {
+ char * tdlm = strpbrk ( (char *)(S->Text+3), ".?!" );
+ if (tdlm && tdlm[0] != '.')
+ tdlm++;
+ if (tdlm)
+ delim = tdlm;
+ }
+ int shLen = delim - (char *)S->Text;
+ S->ShortTextLength = delim == NULL || shLen > numeric_limits<u_char>::max() ? 0 : shLen;
+ LogI(4, prep("EventId %08x Summnr %d:%.30s."), S->EventId, nSummaries, S->Text);
p += Len1;
nSummaries++;
if (nSummaries >= MAX_TITLES) {
@@ -2405,7 +2551,9 @@ void cFilterEEPG::FreeSummaries (void)
S = Summaries[i];
if (i < nSummaries - 1) {
S2 = Summaries[i + 1]; //look at next summary
- if (S->Text != S2->Text && S->Text != 0x00) //this is the last summary that points to this text block; needed in case NumReplays > 1, multiple pointers to same textblock
+ //this is the last summary that points to this text block;
+ // needed in case NumReplays > 1, multiple pointers to same textblock
+ if (S->Text != S2->Text && S->Text != 0x00)
free (S->Text);
} else if (S->Text != 0x00)
free (S->Text);
@@ -2437,21 +2585,26 @@ void cFilterEEPG::LoadIntoSchedule (void)
foundtitle = false;
Title_t *T;
Summary_t *S;
- int remembersummary;
+ int remembersummary = -1;
//keep statistics
int SummariesNotFound = 0;
int NoSummary = 0;
int NotMatching = 0;
int LostSync = 0;
- remembersummary = -1;
+ int OldEvents = 0;
+ int SummIndex = -1;
+ bool isOTV = Format == SKY_IT || Format == SKY_UK;
{
+#if APIVERSNUM >= 20300
+ LOCK_SCHEDULES_WRITE;
+#else
cSchedulesLock SchedulesLock (true);
- cSchedules *s = (cSchedules *) cSchedules::Schedules (SchedulesLock);
- if (s) {
+ cSchedules *Schedules = (cSchedules *) cSchedules::Schedules (SchedulesLock);
+#endif
+ if (Schedules) {
while (i < nTitles) {
- T = Titles[i];
S = Summaries[j];
foundtitle = false;
@@ -2468,13 +2621,16 @@ void cFilterEEPG::LoadIntoSchedule (void)
if (!foundtitle) //no more titles with summaries
break;
- if ((T->EventId == S->EventId) && (T->MjdTime == S->Replays[0].MjdTime)
- && ((T->ChannelId == S->Replays[0].ChannelId) || ((Format != SKY_IT) && (Format != SKY_UK)))) { //should always be true, titles and summaries are broadcasted in order...
+ time_t too_old = time(NULL) - (Setup.EPGLinger * 60 + 3600);
+ if ((T->EventId == S->EventId && T->MjdTime == S->Replays[0].MjdTime) &&
+ ((T->ChannelId == S->Replays[0].ChannelId) || !isOTV)) { //should always be true, titles and summaries are broadcasted in order...
LogD(3, prep("T->EventId == S->EventId"));
//MjdTime = 0 for all but SKY
//S->ChannelId must be equal to T->ChannelId only for SKY; in MHW1 S->ChannelId overrides T->ChannelId when NumReplays > 1
remembersummary = -1; //reset summary searcher
//int Replays = S->NumReplays;
+ if (isOTV)
+ SummIndex = j;
int index = 0;
do {
@@ -2488,14 +2644,21 @@ void cFilterEEPG::LoadIntoSchedule (void)
StartTime = S->Replays[index].StartTime;
}
+ index++;
+ if ((StartTime + (int)T->Duration) < too_old) {
+ LogD(3, prep("Skipping old event '%s', start time:%s"), T->Text, ctime (&StartTime));
+ OldEvents++;
+ continue;
+ }
+
//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);
+ //PrepareToWriteToSchedule (C, Schedules, 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
+ if (isOTV && T->Rating) { //TODO only works on OTV for now
rating = T->Rating;
}
unsigned short int TableId = DEFAULT_TABLE_ID;
@@ -2503,11 +2666,15 @@ void cFilterEEPG::LoadIntoSchedule (void)
TableId = T->TableId;
}
- WriteToSchedule (chanID, s, T->EventId, StartTime, T->Duration / 60, (char *) T->Text,
- (char *) S->Text, T->ThemeId, TableId, 0, rating);
- sortSchedules(s, chanID);
+// LogD (0, prep("EventId %08x Titlenr:%d,SummNr:%d,SummAv:%x,Un1:%x,Un2:%x,Un3:%x,Name:%s,STxtLn:%d,Summary:%s."),
+// T->EventId, i, j, T->SummaryAvailable, T->Unknown1, T->Unknown2, T->Unknown3, T->Text, S->ShortTextLength, S->Text);
+
+ WriteToSchedule (chanID, Schedules, T->EventId, StartTime, T->Duration / 60, (char *) T->Text,
+ (char *) S->Text, T->ThemeId, TableId, 0, rating, S->ShortTextLength);
+ sortSchedules(Schedules, chanID);
+ //if (shortText != NULL) delete [] shortText;
- //FinishWriteToSchedule (C, s, p);
+ //FinishWriteToSchedule (C, Schedules, 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
@@ -2515,11 +2682,9 @@ void cFilterEEPG::LoadIntoSchedule (void)
//j = 0;
//S = Summaries[j]; //next summary within replay range
//}
- index++;
} //while
while (index < S->NumReplays);
- //TODO: why load events that have already past, and then run Cleanup
//end of putting title and summary in schedule
i++; //move to next title
} //if T->EventId == S->EventId
@@ -2532,31 +2697,43 @@ void cFilterEEPG::LoadIntoSchedule (void)
remembersummary = nSummaries; //or next test will never be succesfull for remembersummary = 0
LostSync++;
// esyslog("EEPG Error: lost sync at title %d, summary %d.",i,j);
- } else if (j == (remembersummary - 1)) { //the last summary to be checked has failed also
+ } else if (j == (remembersummary - 1) || SummIndex !=-1) { //the last summary to be checked has failed also
//esyslog ("EEPG Error: could not find summary for summary-available Title %d.", i);
- esyslog
- ("EEPG: Error, summary not found for EventId %08x Titlenr %d:SummAv:%x,Unknown1:%x,Unknown2:%x,Un3:%x,Name:%s.",
- T->EventId, i, T->SummaryAvailable, T->Unknown1, T->Unknown2, T->Unknown3, T->Text);
+ if ((T->StartTime + T->Duration) < (uint)too_old) {
+ LogD(3, prep("Skipping old event '%s' without summary, start time:%s"), T->Text, ctime ((time_t*)&T->StartTime));
+ OldEvents++;
+ } else {
- /* write Title info to schedule */
- sChannel *C = &sChannels[ChannelSeq[T->ChannelId]]; //find channel
- //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 (chanID, s, T->EventId, T->StartTime, T->Duration / 60, (char *) T->Text,
- NULL, T->ThemeId, DEFAULT_TABLE_ID, 0, rating);
- //FinishWriteToSchedule (C, s, p);
- sortSchedules(s, chanID);
+ if (!isOTV) //No sense of logging for SKY when SummaryAvailable bit is not known
+ esyslog("EEPG: Error, summary not found for EventId %08x Titlenr %d:SummAv:%x,Un1:%x,Un2:%x,Un3:%x,Name:%s.",
+ T->EventId, i, T->SummaryAvailable, T->Unknown1, T->Unknown2, T->Unknown3, T->Text);
+
+ /* write Title info to schedule */
+ sChannel *C = &sChannels[ChannelSeq[T->ChannelId]]; //find channel
+ //cSchedule *p;//[MAX_EQUIVALENCES];
+ tChannelID chanID = tChannelID (C->Src, C->Nid, C->Tid, C->Sid);
+ //PrepareToWriteToSchedule (C, Schedules, p);
+ char rating = 0x00;
+ if (!isOTV && T->Rating) { //TODO only works on OTV for now
+ rating = T->Rating;
+ }
+ WriteToSchedule (chanID, Schedules, T->EventId, T->StartTime, T->Duration / 60, (char *) T->Text,
+ NULL, T->ThemeId, DEFAULT_TABLE_ID, 0, rating, S->ShortTextLength);
+ //FinishWriteToSchedule (C, Schedules, p);
+ sortSchedules(Schedules, chanID);
- SummariesNotFound++;
+ SummariesNotFound++;
+ }
i++; //move to next title, for this one no summary can be found
}
-// esyslog("Trying again for this title %d, remember summary %d, but advancing one Summary to %d.",i,remembersummary,j);
+ //Do not loop through summaries for OTV when sumaries and titles are in sync
+ if (SummIndex != -1 && isOTV && nSummaries <= nTitles){
+ j--;
+ }
+
+// if (SummIndex != -1)
+// esyslog("Trying again for this title %d, remember summary %d, but advancing one Summary to %d.",i,remembersummary,j+1);
}
j++; //move to next summary
if (j >= nSummaries) //do not forget to look in beginning of (ring)buffer
@@ -2567,24 +2744,33 @@ void cFilterEEPG::LoadIntoSchedule (void)
LogE (0, prep("Error: could not lock schedules."));
}//release ScheduleLock
- cSchedules::Cleanup (true); //deletes all past events
+ //TODO: Test if cleanup is needed now that old events are no more
+ //one thing it Cleanup (true) does is write the epg.data immediately
+ //cSchedules::Cleanup (true); //deletes all past events
+ cSchedules::Cleanup (); //deletes all past events
- //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);
- if (NoSummary != 0)
+ if (NoSummary)
isyslog ("EEPG: of which %i reported to have no summary available; skipping these BIENTOT titles", NoSummary);
isyslog ("EEPG: found %i summaries", nSummaries);
- if (SummariesNotFound != 0)
- esyslog ("EEPG: %i summaries not found", SummariesNotFound);
+ if (SummariesNotFound) {
+ if (nTitles-nSummaries!=SummariesNotFound) {
+ esyslog ("EEPG: %i summaries not found", SummariesNotFound);
+ esyslog ("EEPG: %i difference between No. of summaries and summaries not found", nTitles-nSummaries-SummariesNotFound);
+ } else
+ isyslog ("EEPG: %i titles without summaries", SummariesNotFound);
+ }
+ if (OldEvents)
+ isyslog ("EEPG: Skipped %i old events", OldEvents);
if (NotMatching > nSummaries)
- LogI (0, prep("Warning: lost sync %i times, summary did not match %i times."),
- LostSync, NotMatching);
+ LogI (0, prep("Warning: lost sync %i times, summary did not match %i times."), LostSync, NotMatching);
+
FreeSummaries (); //do NOT free channels, themes and bouquets here because they will be reused in SKY!
FreeTitles ();
- if (!((Format == SKY_IT) || (Format == SKY_UK))) { //everything but SKY; SKY is the only protocol where LoadIntoSchedule is called repeatedly
+ if (!isOTV) { //everything but SKY; SKY is the only protocol where LoadIntoSchedule is called repeatedly
ChannelSeq.clear ();
}
}
@@ -2593,7 +2779,7 @@ void cFilterEEPG::AddFilter (u_short Pid, u_char Tid)
{
if (!Matches (Pid, Tid)) {
Add (Pid, Tid);
- esyslog (prep("Filter Pid:%x,Tid:%x added."), Pid, Tid);
+ esyslog (prep("Filter Pid:0x%x,Tid:0x%x added."), Pid, Tid);
}
}
@@ -2601,7 +2787,7 @@ void cFilterEEPG::AddFilter (u_short Pid, u_char Tid, unsigned char Mask)
{
if (!Matches (Pid, Tid)) {
Add (Pid, Tid, Mask);
- esyslog (prep("Filter Pid:%x,Tid:%x,Mask:%x added."), Pid, Tid, Mask);
+ esyslog (prep("Filter Pid:0x%x,Tid:0x%x,Mask:0x%x added."), Pid, Tid, Mask);
}
}
@@ -2627,8 +2813,6 @@ void cFilterEEPG::ProcessNextFormat (bool FirstTime = false)
free(mesg);
}
- TitleCounter = 0;
- SummaryCounter = 0;
/*if (SummariesNotFound != 0)
esyslog ("EEPG: %i summaries not found", SummariesNotFound);
else if (VERBOSE >= 1)
@@ -2686,28 +2870,29 @@ void cFilterEEPG::ProcessNextFormat (bool FirstTime = false)
EndThemes = false;
switch (Format) {
case PREMIERE:
- AddFilter (pid, 0xA0);
+ AddFilter (pid, SI::TableIdPremiereCIT);
break;
case MHW1:
- AddFilter (0xd3, 0x92); //ThemesMHW1//TODO: all filters are serialized, strictly speaking Themes is non-fatal...
+ AddFilter (0xd3, SI::TableIdMHW1Themes); //ThemesMHW1//TODO: all filters are serialized, strictly speaking Themes is non-fatal...
break;
case MHW2:
- AddFilter (0x231, 0xc8); //MHW2 Channels & Themes
+ AddFilter (0x231, SI::TableIdMHW2ChannelsThemes); //MHW2 Channels & Themes
break;
case SKY_IT:
case SKY_UK:
- AddFilter (0x11, 0x4a); //Sky Channels
+ GetThemesSKYBOX (); //Sky Themes from file
+ AddFilter (0x11, SI::TableIdSKYChannels); //Sky Channels
break;
case FREEVIEW: //Freeview, CONT mode //TODO streamline this for other modes
InitDictionary ();
- AddFilter (pid, 0x4e, 0xfe); //event info, actual(0x4e)/other(0x4f) TS, present/following
- AddFilter (pid, 0x50, 0xf0); //event info, actual TS, schedule(0x50)/schedule for future days(0x5X)
- AddFilter (pid, 0x60, 0xf0); //event info, other TS, schedule(0x60)/schedule for future days(0x6X)
- AddFilter (0x39, 0x50, 0xf0); //event info, actual TS, Viasat
- AddFilter (0x39, 0x60, 0xf0); //event info, other TS, Viasat
+ AddFilter (pid, SI::TableIdEIT_presentFollowing, 0xfe); //event info, actual(0x4e)/other(0x4f) TS, present/following
+ AddFilter (pid, SI::TableIdEIT_schedule_first, 0xf0); //event info, actual TS, schedule(0x50)/schedule for future days(0x5X)
+ AddFilter (pid, SI::TableIdEIT_schedule_Other_first, 0xf0); //event info, other TS, schedule(0x60)/schedule for future days(0x6X)
+ AddFilter (0x39, SI::TableIdEIT_schedule_first, 0xf0); //event info, actual TS, Viasat
+ AddFilter (0x39, SI::TableIdEIT_schedule_Other_first, 0xf0); //event info, other TS, Viasat
break;
case NAGRA:
- AddFilter (pid, 0xb0); //perhaps TID is equal to first data byte?
+ AddFilter (pid, SI::TableIdNagraCIT); //perhaps TID is equal to first data byte?
break;
case DISH_BEV:
#if APIVERSNUM < 10726
@@ -2719,9 +2904,9 @@ void cFilterEEPG::ProcessNextFormat (bool FirstTime = false)
// AddFilter (0x0441, 0x60, 0xf0); // Bell ExpressVU EEPG
break;
case EIT:
- AddFilter (pid, 0x4e, 0xfe); //event info, actual(0x4e)/other(0x4f) TS, present/following
- AddFilter (pid, 0x50, 0xf0); //event info, actual TS, schedule(0x50)/schedule for future days(0x5X)
- AddFilter (pid, 0x60, 0xf0); //event info, other TS, schedule(0x60)/schedule for future days(0x6X)
+ AddFilter (pid, SI::TableIdEIT_presentFollowing, 0xfe); //event info, actual(0x4e)/other(0x4f) TS, present/following
+ AddFilter (pid, SI::TableIdEIT_schedule_first, 0xf0); //event info, actual TS, schedule(0x50)/schedule for future days(0x5X)
+ AddFilter (pid, SI::TableIdEIT_schedule_Other_first, 0xf0); //event info, other TS, schedule(0x60)/schedule for future days(0x6X)
break;
default:
break;
@@ -2732,25 +2917,36 @@ void cFilterEEPG::ProccessContinuous(u_short Pid, u_char Tid, int Length, const
{
//0x39 Viasat, 0x0300 Dish Network EEPG, 0x0441 Bell ExpressVU EEPG
LogD(4, prep("Pid: 0x%02x Tid: %d Length: %d"), Pid, Tid, Length);
+#if APIVERSNUM >= 20300
+ LOCK_CHANNELS_WRITE;
+ LOCK_SCHEDULES_WRITE;
+// cStateKey SchedulesStateKey;
+// cSchedules *Schedules = cSchedules::GetSchedulesWrite(SchedulesStateKey, 10);
+#else
cSchedulesLock SchedulesLock(true, 10);
cSchedules *Schedules = (cSchedules*)(cSchedules::Schedules(SchedulesLock));
+#endif
//Look for other satelite positions only if Dish/Bell ExpressVU for the moment hardcoded pid check
- if(Schedules)
- SI::cEIT2 EIT(Schedules, Source(), Tid, Data, Format, Pid == EIT_PID);
+ if(Channels && Schedules)
+ SI::cEIT2 EIT(Channels, Schedules, Source(), Tid, Data, Format, Pid == EIT_PID);
+#if APIVERSNUM < 20300
else//cEIT EIT (Schedules, Source (), Tid, Data);
{
// If we don't get a write lock, let's at least get a read lock, so
// that we can set the running status and 'seen' timestamp (well, actually
// with a read lock we shouldn't be doing that, but it's only integers that
// get changed, so it should be ok)
+ cChannelsLock ChannelsLock;
+ cChannels *Channels = (cSchedules*)(cSchedules::Schedules(SchedulesLock));
cSchedulesLock SchedulesLock;
cSchedules *Schedules = (cSchedules*)(cSchedules::Schedules(SchedulesLock));
- if(Schedules)
- SI::cEIT2 EIT(Schedules, Source(), Tid, Data, Format, Pid == EIT_PID, true);
+ if(Channels && Schedules)
+ SI::cEIT2 EIT(Channels, Schedules, Source(), Tid, Data, Format, Pid == EIT_PID, true);
//cEIT EIT (Schedules, Source (), Tid, Data, true);
}
+#endif
}
void cFilterEEPG::Process (u_short Pid, u_char Tid, const u_char * Data, int Length)
@@ -2774,7 +2970,7 @@ void cFilterEEPG::Process (u_short Pid, u_char Tid, const u_char * Data, int Len
if (idx++ == pmtidx) {
pmtpid = assoc.getPid ();
pmtsid = assoc.getServiceId ();
- Add (pmtpid, 0x02);
+ Add (pmtpid, SI::TableIdPMT);
pmtnext = now + PMT_SCAN_TIMEOUT;
LogI(3, prep("PMT pid now 0x%04x (idx=%d)\n"), pmtpid, pmtidx);
break;
@@ -2811,7 +3007,7 @@ void cFilterEEPG::Process (u_short Pid, u_char Tid, const u_char * Data, int Len
usrFRV = 1;
LogD(4, prep("if (data[2]==0x39) {//TODO Test This"));
}
- //Format = 0; // 0 = premiere, 1 = MHW1, 2 = MHW2, 3 = Sky Italy (OpenTV), 4 = Sky UK (OpenTV), 5 = Freesat (Freeview), 6 = Nagraguide
+
SI::Descriptor * d;
unsigned char nDescriptorTag;
for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext (it));) {
@@ -2827,36 +3023,35 @@ void cFilterEEPG::Process (u_short Pid, u_char Tid, const u_char * Data, int Len
if (d->getLength () == 6 && d->getData ().FourBytes (2) == 0x46534154) //Freeview
prvFRV = true;
break;
- case 0x52:
+ case SI::StreamIdentifierDescriptorTag:
//if (d->getLength () == 3 && d->getData ().FourBytes (2) == 0xb07ea882) {
if (d->getLength () == 3 && ((d->getData ().TwoBytes (2) & 0xff00) == 0xb000))
UnprocessedFormat[NAGRA] = stream.getPid ();
break;
- case 0x90:
+ case SI::SkyOTVDescriptorTag:
//esyslog ("usr: %d %08x\n", d->getLength (), d->getData ().FourBytes (2));
if (d->getLength () == 6 && d->getData ().FourBytes (2) == 0x0000ffff)
usrData = true;
if (d->getLength () == 3 && ((d->getData ().TwoBytes (2) & 0xff00) == 0xb600)) //SKY IT //TODO ugly!
- //if (d->getLength () == 3 && (d->getData ().TwoBytes (2) == 0xb6a5)) //SKY IT //TODO ugly!
usrOTV = SKY_IT;
//Format = SKY_IT;
if (d->getLength () == 3 && d->getData ().FourBytes (2) == 0xc004e288) //SKY UK
usrOTV = SKY_UK;
//Format = SKY_UK;
break;
- case 0xc1: //MHW1, MHW2
+ case SI::MHW1DescriptorTag: //MHW1, MHW2
// esyslog("EEPGDEBUG:d->getDescriptorTAG:%d %08x\n",d->getLength(),d->getData().FourBytes(2));
if (d->getLength () == 10 && d->getData ().FourBytes (2) == 0x50555348) //MHw1 Cyfra
UnprocessedFormat[MHW1] = stream.getPid ();
break;
- case 0xc2: //MHW1, MHW2
+ case SI::MHW1_2DescriptorTag: //MHW1, MHW2
if (d->getLength () == 10 && d->getData ().FourBytes (2) == 0x45504700) //MHw1 CanDigNL and CSat
UnprocessedFormat[MHW1] = stream.getPid ();
else if (d->getLength () == 10 && d->getData ().FourBytes (2) == 0x46494348) { //MHW2
UnprocessedFormat[MHW2] = stream.getPid ();
}
break;
- case 0xd1: //Freeview
+ case SI::FreeviewDescriptorTag: //Freeview
LogD(4, prep("case 0xd1: //Freeview"));
if (d->getLength () == 3 && ((d->getData ().TwoBytes (2) & 0xff00) == 0x0100))
usrFRV = 0x01;
@@ -2913,39 +3108,34 @@ void cFilterEEPG::Process (u_short Pid, u_char Tid, const u_char * Data, int Len
else if (Source ()) {
if ( Pid == EIT_PID || Pid == 0x0300 || Pid == 0x0441 ) {
- if (Tid >= 0x4E)
+ if (Tid >= SI::TableIdEIT_presentFollowing)
ProccessContinuous(Pid, Tid, Length, Data);
return;
}
int Result;
switch (Tid) {
- case 0xA0:
+ case SI::TableIdPremiereCIT:
if ((Pid < 0x30) || (Pid > 0x37)) {
ProcessPremiere(Data);
break;
} //if citpid == 0xb11 Premiere
/* no break - used for sky also*/
- case 0xa1:
- case 0xa2:
- case 0xa3:
+ case SI::TableIdSKYTitles_first ... SI::TableIdSKYTitles_last:
Result = GetTitlesSKYBOX (Data, Length - 4);
if (Result != 1) //when fatal error or finished
- Del (Pid, 0xa0, 0xfc); //kill filter
+ Del (Pid, SI::TableIdSKYTitlesA0, 0xfc); //kill filter
if (Result == 0) { //fatal error
esyslog ("EEPG: Fatal error reading titles.");
ProcessNextFormat (); //and go process other formats
}
if (Result == 2)
- AddFilter (Pid + 0x10, 0xa8, 0xfc); //Set filter that processes summaries of this batch
+ AddFilter (Pid + 0x10, SI::TableIdSKYSummaries_first, 0xfc); //Set filter that processes summaries of this batch
break;
- case 0xa8:
- case 0xa9:
- case 0xaa:
- case 0xab:
+ case SI::TableIdSKYSummaries_first ... SI::TableIdSKYSummaries_last:
Result = GetSummariesSKYBOX (Data, Length - 4);
if (Result != 1) //when fatal error or finished
- Del (Pid, 0xa8, 0xfc); //kill filter
+ Del (Pid, SI::TableIdSKYSummaries_first, 0xfc); //kill filter
if (Result == 0) {
esyslog ("EEPG: Fatal error reading summaries.");
ProcessNextFormat ();
@@ -2953,12 +3143,12 @@ void cFilterEEPG::Process (u_short Pid, u_char Tid, const u_char * Data, int Len
if (Result == 2) {
LoadIntoSchedule ();
if (Pid < 0x47) //this is not the last batch//FIXME chaining is easy on the PIDs and the CPU, but error when Pid,Tid is not used at the moment...
- AddFilter (Pid - 0x0F, 0xa0, 0xfc); //next pid, first tid
+ AddFilter (Pid - 0x0F, SI::TableIdSKYTitlesA0, 0xfc); //next pid, first tid
else //last pid was processed
ProcessNextFormat ();
}
break;
- case 0x90:
+ case SI::TableIdMHW1TitlesSummaries:
if (Pid == 0xd2) {
Result = GetTitlesMHW1 (Data, Length);
if (Result != 1) //fatal error or last processed
@@ -2968,7 +3158,7 @@ void cFilterEEPG::Process (u_short Pid, u_char Tid, const u_char * Data, int Len
ProcessNextFormat ();
}
if (Result == 2)
- AddFilter (0xd3, 0x90); //SummariesMHW1
+ AddFilter (0xd3, SI::TableIdMHW1TitlesSummaries); //SummariesMHW1
} else if (Pid == 0xd3) {
Result = GetSummariesMHW1 (Data, Length);
if (Result != 1) //fatal error or last processed
@@ -2984,24 +3174,24 @@ void cFilterEEPG::Process (u_short Pid, u_char Tid, const u_char * Data, int Len
}
}
break;
- case 0xc8: //GetChannelsMHW2 or GetThemesMHW2
+ case SI::TableIdMHW2ChannelsThemes: //GetChannelsMHW2 or GetThemesMHW2
if (Pid == 0x231) {
if (Data[3] == 0x01) { //Themes it will be
- Result = GetThemesMHW2 (Data, Length); //return code 0 = fatal error, code 1 = sucess, code 2 = last item processed
+ Result = GetThemesMHW2 (Data, Length); //return code 0 = fatal error, code 1 = success, code 2 = last item processed
//break;
if (Result != 1)
EndThemes = true; //also set Endthemes on true on fatal error
} //if Data
else if (Data[3] == 0x00) { //Channels it will be
- Result = GetChannelsMHW (Data, Length, 2); //return code 0 = fatal error, code 1 = sucess, code 2 = last item processed
+ Result = GetChannelsMHW (Data, Length); //return code 0 = fatal error, code 1 = success, code 2 = last item processed
if (Result != 1)
EndChannels = true; //always remove filter, code 1 should never be returned since MHW2 always reads all channels..
ChannelsOk = (Result == 2);
}
- if (EndChannels && EndThemes) { //those are only set withing MHW2
- Del (0x231, 0xc8); //stop reading MHW2 themes and channels
- if (ChannelsOk) //No channels = fatal, no themes = nonfatal
- AddFilter (0x234, 0xe6); //start reading MHW2 titles
+ if (EndChannels && EndThemes) { //those are only set within MHW2
+ Del (0x231, SI::TableIdMHW2ChannelsThemes); //stop reading MHW2 themes and channels
+ if (ChannelsOk) //No channels = fatal, no themes = non fatal
+ AddFilter (0x234, SI::TableIdMHW2Titles); //start reading MHW2 titles
else {
esyslog ("EEPG: Fatal error reading channels.");
ProcessNextFormat ();
@@ -3009,30 +3199,30 @@ void cFilterEEPG::Process (u_short Pid, u_char Tid, const u_char * Data, int Len
}
} //if Pid == 0x231
break;
- case 0x91:
- Result = GetChannelsMHW (Data, Length, 1); //return code 0 = fatal error, code 1 = sucess, code 2 = last item processed
+ case SI::TableIdMHW1Channels:
+ Result = GetChannelsMHW (Data, Length); //return code 0 = fatal error, code 1 = success, code 2 = last item processed
Del (Pid, Tid); //always remove filter, code 1 should never be returned since MHW1 always reads all channels...
if (Result == 2)
- AddFilter (0xd2, 0x90); //TitlesMHW1
+ AddFilter (0xd2, SI::TableIdMHW1TitlesSummaries); //TitlesMHW1
else {
esyslog ("EEPG: Fatal error reading channels.");
ProcessNextFormat ();
}
break;
- case 0x92:
- Result = GetThemesMHW1 (Data, Length); //return code 0 = fatal error, code 1 = sucess, code 2 = last item processed
+ case SI::TableIdMHW1Themes:
+ Result = GetThemesMHW1 (Data, Length); //return code 0 = fatal error, code 1 = success, code 2 = last item processed
if (Result != 1)
Del (Pid, Tid);
if (Result == 2)
- AddFilter (0xd3, 0x91); //ChannelsMHW1
+ AddFilter (0xd3, SI::TableIdMHW1Channels); //ChannelsMHW1
else {
- esyslog ("EEPG: Fatal error reading themes."); //doesnt have to be fatal...
+ esyslog ("EEPG: Fatal error reading themes."); //Doesn't have to be fatal...
ProcessNextFormat ();
}
break;
- case 0xe6: //TitlesMHW2
+ case SI::TableIdMHW2Titles: //TitlesMHW2
if (Pid == 0x234) {
- Result = GetTitlesMHW2 (Data, Length); //return code 0 = fatal error, code 1 = sucess, code 2 = last item processed
+ Result = GetTitlesMHW2 (Data, Length); //return code 0 = fatal error, code 1 = success, code 2 = last item processed
if (Result != 1)
Del (Pid, Tid);
if (Result == 0) {
@@ -3040,10 +3230,10 @@ void cFilterEEPG::Process (u_short Pid, u_char Tid, const u_char * Data, int Len
ProcessNextFormat ();
}
if (Result == 2)
- AddFilter (0x236, 0x96); //start reading MHW2 summaries....
+ AddFilter (0x236, SI::TableIdMHW2Summaries); //start reading MHW2 summaries....
}
break;
- case 0x96: //Summaries MHW2
+ case SI::TableIdMHW2Summaries: //Summaries MHW2
if (Pid == 0x236) {
Result = GetSummariesMHW2 (Data, Length); //return code 0 = fatal error, code 1 = sucess, code 2 = last item processed
if (Result != 1)
@@ -3058,15 +3248,14 @@ void cFilterEEPG::Process (u_short Pid, u_char Tid, const u_char * Data, int Len
}
} //if pid
break;
- case 0x4a: //Sky channels
+ case SI::TableIdSKYChannels: //Sky channels
if (Pid == 0x11) {
Result = GetChannelsSKYBOX (Data, Length - 4);
if (Result != 1) //only breakoff on completion or error; do NOT clean up after success, because then not all bouquets will be read
Del (Pid, Tid); //Read all channels, clean up filter
if (Result == 2) {
- GetThemesSKYBOX (); //Sky Themes from file; must be called AFTER first channels to have lThemes initialized FIXME
if (InitDictionary ())
- AddFilter (0x30, 0xa0, 0xfc); //SKY Titles batch 0 of 7
+ AddFilter (0x30, SI::TableIdSKYTitlesA0, 0xfc); //SKY Titles batch 0 of 7
else {
esyslog ("EEPG: Fatal error reading huffman table.");
ProcessNextFormat ();
@@ -3075,7 +3264,7 @@ void cFilterEEPG::Process (u_short Pid, u_char Tid, const u_char * Data, int Len
} //if Pid == 0x11
break;
- case 0xb0: //NagraGuide
+ case SI::TableIdNagraCIT: //NagraGuide
if (Pid == 0xc8) {
Result = GetNagra (Data, Length);
if (Result != 1)
@@ -3094,40 +3283,9 @@ void cFilterEEPG::Process (u_short Pid, u_char Tid, const u_char * Data, int Len
}
break;
- case 0x4E:
- case 0x4F:
- case 0x50:
- case 0x51:
- case 0x52:
- case 0x53:
- case 0x54:
- case 0x55:
- case 0x56:
- case 0x57:
- case 0x58:
- case 0x59:
- case 0x5A:
- case 0x5B:
- case 0x5C:
- case 0x5D:
- case 0x5E:
- case 0x5F:
- case 0x60:
- case 0x61:
- case 0x62:
- case 0x63:
- case 0x64:
- case 0x65:
- case 0x66:
- case 0x67:
- case 0x68:
- case 0x69:
- case 0x6A:
- case 0x6B:
- case 0x6C:
- case 0x6D:
- case 0x6E:
- case 0x6F:
+ case SI::TableIdEIT_presentFollowing:
+ case SI::TableIdEIT_presentFollowing_other:
+ case SI::TableIdEIT_schedule_first ... SI::TableIdEIT_schedule_Other_last:
// Freesat:
// Set(3842, 0x4E, 0xFE); // event info, actual(0x4E)/other(0x4F) TS, present/following
// Set(3842, 0x50, 0xF0); // event info, actual TS, schedule(0x50)/schedule for future days(0x5X)
@@ -3156,13 +3314,17 @@ void cFilterEEPG::ProcessPremiere(const u_char *& Data)
SI::PremiereCIT cit(Data, false);
if (cit.CheckCRCAndParse ()) {
+#if APIVERSNUM >= 20300
+ LOCK_SCHEDULES_WRITE;
+#else
cSchedulesLock SchedulesLock (true, 10);
cSchedules *Schedules = (cSchedules *) cSchedules::Schedules (SchedulesLock);
+#endif
if (Schedules) {
int now = time (0);
int nCount = 0;
int nRating = 0;
- unsigned char Tid = 0xa0; // TODO maybe default TableID
+ unsigned char Tid = SI::TableIdPremiereCIT; // TODO maybe default TableID
SI::ExtendedEventDescriptors * ExtendedEventDescriptors = 0;
SI::ShortEventDescriptor * ShortEventDescriptor = 0;
char *order = 0, *rating = 0;
@@ -3176,7 +3338,7 @@ void cFilterEEPG::ProcessPremiere(const u_char *& Data)
for (SI::Loop::Iterator it; (d = cit.eventDescriptors.getNext (it));) {
nDescriptorTag = d->getDescriptorTag ();
switch (nDescriptorTag) {
- case 0xF0: // order information
+ case SI::PremiereOrderInfoDescriptorTag: // order information
if (SetupPE->OrderInfo) {
static const char *text[] = {
trNOOP ("Ordernumber"),
@@ -3198,7 +3360,7 @@ void cFilterEEPG::ProcessPremiere(const u_char *& Data)
order = strdup (buff);
}
break;
- case 0xF1: // parental rating
+ case SI::PremiereRatingInfoDescriptorTag: // parental rating
if (SetupPE->RatingInfo) {
char buff[512];
int p = 0;
@@ -3281,14 +3443,13 @@ void cFilterEEPG::ProcessPremiere(const u_char *& Data)
int sid = pct->getServiceId ();
if (SetupPE->FixEpg) {
if (nid == 133) {
- if (tid == 0x03 && sid == 0xf0) {
- tid = 0x02;
+ if (tid == SI::TableIdTSDT && sid == 0xf0) {
+ tid = SI::TableIdPMT;
sid = 0xe0;
- } else if (tid == 0x03 && sid == 0xf1) {
- tid = 0x02;
+ } else if (tid == SI::TableIdTSDT && sid == 0xf1) {
+ tid = SI::TableIdPMT;
sid = 0xe1;
- } else if (tid == 0x03 && sid == 0xf5) {
- tid = 0x03;
+ } else if (tid == SI::TableIdTSDT && sid == 0xf5) {
sid = 0xdc;
} else if (tid == 0x04 && sid == 0xd2) {
tid = 0x11;
@@ -3300,7 +3461,12 @@ void cFilterEEPG::ProcessPremiere(const u_char *& Data)
}
}
tChannelID channelID (Source (), nid, tid, sid);
+#if APIVERSNUM >= 20300
+ LOCK_CHANNELS_READ;
+ const cChannel *channel = Channels->GetByChannelID (channelID, true);
+#else
cChannel *channel = Channels.GetByChannelID (channelID, true);
+#endif
if (!channel)
continue;
@@ -3349,7 +3515,7 @@ void cFilterEEPG::ProcessPremiere(const u_char *& Data)
} else {
LogI(2, "(upd)\n");
pEvent->SetSeen ();
- if (pEvent->TableID () == 0x00 || pEvent->Version () == cit.getVersionNumber ()) {
+ if (pEvent->TableID () == SI::TableIdPAT || pEvent->Version () == cit.getVersionNumber ()) {
if (pEvent->RunningStatus () != runningStatus)
pSchedule->SetRunningStatus (pEvent, runningStatus, channel);
continue;
@@ -3405,7 +3571,11 @@ void cFilterEEPG::ProcessPremiere(const u_char *& Data)
}
if (Modified) {
pSchedule->Sort ();
+#if APIVERSNUM >= 20300
+ pSchedule->SetModified();
+#else
Schedules->SetModified (pSchedule);
+#endif
}
delete pct;
}
@@ -3524,14 +3694,19 @@ bool cPluginEEPG::Start (void)
CheckCreateFile("sky_uk.themes", SkyUkThemes);
CheckCreateFile("freesat.t1", FreesatT1);
CheckCreateFile("freesat.t2", FreesatT2);
- CheckCreateFile("sky_uk.themes", SkyUkThemes);
+ load_theme_dictionaries();
sky_tables[0] = NULL;
sky_tables[1] = NULL;
tables[0][0] = NULL;
//store all available sources, so when a channel is not found on current satellite, we can look for alternate sat positions.
//perhaps this can be done smarter through existing VDR function???
- for (cChannel * Channel = Channels.First (); Channel; Channel = Channels.Next (Channel)) {
+#if APIVERSNUM >= 20300
+ LOCK_CHANNELS_READ;
+ for (const cChannel * Channel = Channels->First(); Channel; Channel = Channels->Next(Channel)) {
+#else
+ for (const cChannel * Channel = Channels.First (); Channel; Channel = Channels.Next (Channel)) {
+#endif
if (!Channel->GroupSep ()) {
bool found = false;
for (int i = 0; (i < NumberOfAvailableSources) && (!found); i++)
@@ -3590,17 +3765,6 @@ cMenuSetupPage *cPluginEEPG::SetupMenu (void)
bool cPluginEEPG::SetupParse (const char *Name, const char *Value)
{
-// LogF(0, "!!!! Dime test LogF");
-// LogF(0, "!!!! Dime test LogF %d", 2);
-// LogI(0, "!!!! Dime test LogI");
-// LogI(0, "!!!! Dime test LogI %d", 2);
-// LogI(0, prep2("!!!! Dime test prep"));
-// LogI(0, prep2("!!!! Dime test prep %d"), 2);
-// LogD(0, "!!!! Dime test LogD");
-// LogD(0, "!!!! Dime test LogD %d", 2);
-// LogE(0, "!!!! Dime test LogE");
-// LogE(0, "!!!! Dime test LogE %d", 2);
-
if (!strcasecmp (Name, "OptionPattern"))
SetupPE->OptPat = atoi (Value);
@@ -3612,6 +3776,10 @@ bool cPluginEEPG::SetupParse (const char *Name, const char *Value)
SetupPE->FixEpg = atoi (Value);
else if (!strcasecmp (Name, "DisplayMessage"))
SetupPE->DisplayMessage = atoi (Value);
+ else if (!strcasecmp (Name, "ReplaceEmptyShText"))
+ SetupPE->ReplaceEmptyShText = atoi (Value);
+ else if (!strcasecmp (Name, "FixCharset"))
+ SetupPE->FixCharset = atoi (Value);
#ifdef DEBUG
else if (!strcasecmp (Name, "LogLevel"))
SetupPE->LogLevel = atoi (Value);
diff --git a/eepg.h b/eepg.h
index 7e1cc74..6c84051 100644
--- a/eepg.h
+++ b/eepg.h
@@ -57,6 +57,7 @@ typedef struct {
unsigned char Unknown2;//FIXME
unsigned char Unknown3;//FIXME
unsigned char Rating;
+ unsigned char Quality;
unsigned short int TableId;
} Title_t;
@@ -70,6 +71,7 @@ typedef struct {
unsigned int EventId;//short is not sufficient for Nagra
unsigned short int NumReplays;
unsigned char * Text;
+ unsigned char ShortTextLength;
} Summary_t;
@@ -1207,7 +1209,7 @@ static const char *SkyItThemes[] = {
"Intrattenimento - Festival", // 001 10001
"Intrattenimento - Teatro", // 001 10010
"Intrattenimento - Gioco", // 001 10011
- NULL, // 001 10100
+ "Intrattenimento - Manga", // 001 10100
NULL, // 001 10101
NULL, // 001 10110
NULL, // 001 10111
@@ -1237,11 +1239,11 @@ static const char *SkyItThemes[] = {
"Sport - Golf", // 010 01111
"Sport - Nuoto", // 010 10000
"Sport - Wrestling", // 010 10001
- NULL, // 010 10010
- NULL, // 010 10011
- NULL, // 010 10100
- NULL, // 010 10101
- NULL, // 010 10110
+ "Sport - Pallamano", // 010 10010
+ "Sport - Volley", // 010 10011
+ "Sport - Poker", // 010 10100
+ "Sport - Vela", // 010 10101
+ "Sport - Sport Invernali", // 010 10110
NULL, // 010 10111
NULL, // 010 11000
NULL, // 010 11001
@@ -1269,7 +1271,7 @@ static const char *SkyItThemes[] = {
"Film - Musicale", // 011 01111
"Film - Corto", // 011 10000
"Film - Cortometraggio", // 011 10001
- NULL, // 011 10010
+ "Film - Erotico", // 011 10010
NULL, // 011 10011
NULL, // 011 10100
NULL, // 011 10101
@@ -1356,19 +1358,19 @@ static const char *SkyItThemes[] = {
"Ragazzi e Musica - Film", // 110 00110
"Ragazzi e Musica - Telefilm", // 110 00111
"Ragazzi e Musica - Magazine", // 110 01000
- NULL, // 110 01001
+ "Ragazzi e Musica - Giochi", // 110 01001
NULL, // 110 01010
- NULL, // 110 01011
+ "Ragazzi e Musica - Musica da Camera", // 110 01011
NULL, // 110 01100
NULL, // 110 01101
- NULL, // 110 01110
+ "Ragazzi e Musica - Classica", // 110 01110
NULL, // 110 01111
NULL, // 110 10000
- NULL, // 110 10001
+ "Ragazzi e Musica - Concerto", // 110 10001
NULL, // 110 10010
NULL, // 110 10011
"Ragazzi e Musica - Danza", // 110 10100
- NULL, // 110 10101
+ "Ragazzi e Musica - Videoclip", // 110 10101
NULL, // 110 10110
NULL, // 110 10111
NULL, // 110 11000
@@ -1383,7 +1385,7 @@ static const char *SkyItThemes[] = {
"Altri Programmi - Educational", // 111 00001
"Altri Programmi - Regionale", // 111 00010
"Altri Programmi - Shopping", // 111 00011
- NULL, // 111 00100
+ "Altri Programmi - Altri", // 111 00100
"Altri Programmi - Inizio e Fine Trasmissioni", // 111 00101
"Altri Programmi - Eventi Speciali", // 111 00110
"Altri Programmi - Film per Adulti", // 111 00111
@@ -1446,11 +1448,11 @@ static const char *SkyUkThemes[] = {
NULL, // 000 11101
NULL, // 000 11110
NULL, // 000 11111
- NULL, // 001 00000
+ "Specialist - Shopping", // 001 00000
NULL, // 001 00001
NULL, // 001 00010
"Shopping", // 001 00011
- NULL, // 001 00100
+ "Specialist - Gaming", // 001 00100
NULL, // 001 00101
NULL, // 001 00110
NULL, // 001 00111
@@ -1486,8 +1488,8 @@ static const char *SkyUkThemes[] = {
"Children - Under 5", // 010 00101
"Children - Factual", // 010 00110
"Children - Magazine", // 010 00111
- NULL, // 010 01000
- NULL, // 010 01001
+ "Children - Games Shows", // 010 01000
+ "Children - Games", // 010 01001
NULL, // 010 01010
NULL, // 010 01011
NULL, // 010 01100
@@ -1516,7 +1518,7 @@ static const char *SkyUkThemes[] = {
"Entertainment - Detective", // 011 00011
"Entertainment - Drama", // 011 00100
"Entertainment - Game Show", // 011 00101
- "Entertainment - Sci-FI", // 011 00110
+ "Entertainment - Sci-Fi", // 011 00110
"Entertainment - Soap", // 011 00111
"Entertainment - Animation", // 011 01000
"Entertainment - Chat Show", // 011 01001
@@ -1543,7 +1545,7 @@ static const char *SkyUkThemes[] = {
NULL, // 011 11110
NULL, // 011 11111
"Music", // 100 00000
- "Music - Classical ", // 100 00001
+ "Music - Classical", // 100 00001
"Music - Folk and Country", // 100 00010
"Music - National Music", // 100 00011
"Music - Jazz", // 100 00100
@@ -1555,14 +1557,14 @@ static const char *SkyUkThemes[] = {
"Music - Hip Hop", // 100 01010
"Music - Soul/R&B", // 100 01011
"Music - Dance", // 100 01100
- NULL, // 100 01101
+ "Music - Ballet", // 100 01101
NULL, // 100 01110
NULL, // 100 01111
"Music - Features", // 100 10000
NULL, // 100 10001
- NULL, // 100 10010
+ "Music - Factual", // 100 10010
NULL, // 100 10011
- NULL, // 100 10100
+ "Music - Comedy", // 100 10100
"Music - Lifestyle", // 100 10101
"Music - News and Weather", // 100 10110
"Music - Easy Listening", // 100 10111
@@ -1593,11 +1595,11 @@ static const char *SkyUkThemes[] = {
"News & Documentaries - Transport", // 101 10000
"News & Documentaries - Docudrama", // 101 10001
"News & Documentaries - World Affairs", // 101 10010
- NULL, // 101 10011
- NULL, // 101 10100
- NULL, // 101 10101
+ "News & Documentaries - Features", // 101 10011
+ "News & Documentaries - Showbiz", // 101 10100
+ "News & Documentaries - Politics", // 101 10101
NULL, // 101 10110
- NULL, // 101 10111
+ "News & Documentaries - World Affairs", // 101 10111
NULL, // 101 11000
NULL, // 101 11001
NULL, // 101 11010
@@ -1625,7 +1627,7 @@ static const char *SkyUkThemes[] = {
"Movie - Fantasy", // 110 10000
"Movie - Erotic", // 110 10001
"Movie - Adventure", // 110 10010
- NULL, // 110 10011
+ "Movie - War", // 110 10011
NULL, // 110 10100
NULL, // 110 10101
NULL, // 110 10110
@@ -7179,4 +7181,14 @@ typedef struct { //first three bytes form unknown header, then X blocks, where X
#define HILO16( x ) ( ( ( x##High << 8 ) | x##Low ) & 0xffff )
#define HILO32( x ) ( ( ( ( ( x##High << 24 ) | ( x##MediumHigh << 16 ) ) | ( x##MediumLow << 8 ) ) | x##Low ) & 0xffffffff )
-#define MjdToEpochTime(x) (((x##_hi << 8 | x##_lo)-40587)*86400)
+//#define MjdToEpochTime(x) (((x##_hi << 8 | x##_lo)-40587)*86400)
+inline time_t MjdToEpochTime(u_short mjd, u_char Hour = 0, u_char Minute = 0, u_char Sec = 0) {
+ return ((mjd - 40587) * 86400) + ( ((((Hour & 0xf0) >> 4) * 10) + (Hour & 0x0f)) * 3600 )
+ + (((((Minute & 0xf0) >> 4) * 10) + (Minute & 0x0f)) * 60)
+ + ((((Sec & 0xf0) >> 4) * 10) + (Sec & 0x0f));
+}
+inline time_t MjdToEpochTime(u_char dateHigh, u_char dateLow, u_char Hour = 0, u_char Minute = 0,u_char Sec = 0) {
+ unsigned short mjd = HILO16(date);
+ return MjdToEpochTime(mjd, Hour, Minute, Sec);
+}
+
diff --git a/eit2.c b/eit2.c
index d5f928b..a8b0561 100644
--- a/eit2.c
+++ b/eit2.c
@@ -76,14 +76,21 @@ cEvent* cEIT2::ProcessEitEvent(cSchedule* pSchedule,const SI::EIT::Event* EitEve
pSchedule->AddEvent (newEvent);
if (Tid == 0x4E) { // we trust only the present/following info on the actual TS
if (EitEvent->getRunningStatus () >= SI::RunningStatusNotRunning)
- pSchedule->SetRunningStatus (pEvent, EitEvent->getRunningStatus (), channel);
+ {
+#if APIVERSNUM >= 20300
+ pSchedule->SetRunningStatus (pEvent, EitEvent->getRunningStatus (), channel);
+#else
+ cChannel* chan = Channels.GetByChannelID(channel->GetChannelID());
+ pSchedule->SetRunningStatus (pEvent, EitEvent->getRunningStatus (), chan);
+#endif
+ }
}
if (OnlyRunningStatus)
return NULL; // do this before setting the version, so that the full update can be done later
pEvent->SetVersion (versionNumber);
ProcessEventDescriptors(ExternalData, channel->Source(), Tid, EitEvent,
- pEvent, Schedules, channel);
+ pEvent, Schedules, channel->GetChannelID());
Modified = true;
return pEvent;
@@ -91,7 +98,7 @@ cEvent* cEIT2::ProcessEitEvent(cSchedule* pSchedule,const SI::EIT::Event* EitEve
void cEIT2::ProcessEventDescriptors(bool ExternalData, int Source,
u_char Tid, const SI::EIT::Event* SiEitEvent, cEvent* pEvent,
- cSchedules* Schedules, cChannel* channel)
+ cSchedules* Schedules, const tChannelID& channelId)
{
cEvent *rEvent = NULL;
@@ -110,6 +117,11 @@ void cEIT2::ProcessEventDescriptors(bool ExternalData, int Source,
cLinkChannels *LinkChannels = NULL;
cComponents *Components = NULL;
+#if APIVERSNUM >= 20300
+ cChannel *channel = Channels->GetByChannelID(channelId);
+#else
+ cChannel *channel = Channels.GetByChannelID(channelId);
+#endif
DescriptorLoop dl = SiEitEvent->eventDescriptors;
for (SI::Loop::Iterator it2; (d = dl.getNext(it2)); )
@@ -247,7 +259,11 @@ void cEIT2::ProcessEventDescriptors(bool ExternalData, int Source,
char linkName[ld->privateData.getLength() + 1];
strn0cpy(linkName, (const char *) ld->privateData.getData(), sizeof(linkName));
// TODO is there a standard way to determine the character set of this string?
+#if APIVERSNUM >= 20300
+ cChannel *link = Channels->GetByChannelID(linkID);
+#else
cChannel *link = Channels.GetByChannelID(linkID);
+#endif
if (link != channel) { // only link to other channels, not the same one
//fprintf(stderr, "Linkage %s %4d %4d %5d %5d %5d %5d %02X '%s'\n", hit ? "*" : "", channel->Number(), link ? link->Number() : -1, SiEitEvent.getEventId(), ld->getOriginalNetworkId(), ld->getTransportStreamId(), ld->getServiceId(), ld->getLinkageType(), linkName);//XXX
if (link) {
@@ -255,10 +271,15 @@ void cEIT2::ProcessEventDescriptors(bool ExternalData, int Source,
link->SetName(linkName, "", "");
}
else if (Setup.UpdateChannels >= 4) {
- cChannel *transponder = channel;
+ const cChannel *transponder = channel;
if (channel->Tid() != ld->getTransportStreamId())
+#if APIVERSNUM >= 20300
+ transponder = Channels->GetByTransponderID(linkID);
+ link = Channels->NewChannel(transponder, linkName, "", "", ld->getOriginalNetworkId(),
+#else
transponder = Channels.GetByTransponderID(linkID);
link = Channels.NewChannel(transponder, linkName, "", "", ld->getOriginalNetworkId(),
+#endif
ld->getTransportStreamId(), ld->getServiceId());
}
if (link) {
@@ -438,9 +459,10 @@ void cEIT2::ProcessEventDescriptors(bool ExternalData, int Source,
channel->SetLinkChannels (LinkChannels);
}
-cEIT2::cEIT2 (cSchedules * Schedules, int Source, u_char Tid, const u_char * Data, EFormat format, bool isEITPid, bool OnlyRunningStatus)
+cEIT2::cEIT2 (cChannels* Channels, cSchedules * Schedules, int Source, u_char Tid, const u_char * Data, EFormat format, bool isEITPid, bool OnlyRunningStatus)
: SI::EIT (Data, false)
, OnlyRunningStatus(OnlyRunningStatus)
+, Channels(Channels)
, Schedules(Schedules)
, Format(format)
{
@@ -549,8 +571,15 @@ cEIT2::cEIT2 (cSchedules * Schedules, int Source, u_char Tid, const u_char * Dat
////
if (Empty && Tid == 0x4E && getSectionNumber () == 0)
- // ETR 211: an empty entry in section 0 of table 0x4E means there is currently no event running
- pSchedule->ClrRunningStatus (channel);
+ // ETR 211: an empty entry in section 0 of table 0x4E means there is currently no event running
+ {
+#if APIVERSNUM >= 20300
+ cChannel *chan = Channels->GetByChannelID(channel->GetChannelID());
+#else
+ cChannel *chan = Channels.GetByChannelID(channel->GetChannelID());
+#endif
+ pSchedule->ClrRunningStatus (chan);
+ }
if (Tid == 0x4E)
pSchedule->SetPresentSeen ();
if (OnlyRunningStatus) {
diff --git a/eit2.h b/eit2.h
index c85a9d3..65d4b82 100644
--- a/eit2.h
+++ b/eit2.h
@@ -9,11 +9,38 @@
using namespace util;
namespace SI
{
+
+enum TableIdExt {
+ TableIdSKYChannels = TableIdBAT, //SKYBOX channels information section 0x4A same as TableIdBAT
+ TableIdMHW1TitlesSummaries = 0x90, //MHW1 titles and summaries information section
+ TableIdMHW1Channels = 0x91, //MHW1 channels information section
+ TableIdMHW1Themes = 0x92, //MHW1 themes information section
+ TableIdMHW2Summaries = 0x96, //MHW2 summaries information section
+ //SKYBOX Titles range from 0xA0 to 0xA3. 0xA0 is also TableIdPremiereCIT
+ TableIdSKYTitlesA0 = TableIdPremiereCIT, //SKYBOX titles information section start
+ TableIdSKYTitles_first = 0xA1, //SKYBOX titles information section start
+ TableIdSKYTitles_last = 0xA3, //SKYBOX titles information section end
+ //SKYBOX Summaries range from 0xA8 to 0xAB.
+ TableIdSKYSummaries_first = 0xA8, //SKYBOX Summaries information section start
+ TableIdSKYSummaries_last = 0xAB, //SKYBOX Summaries information section end
+ TableIdNagraCIT = 0xB0, //NagraGuide content information section
+ TableIdMHW2ChannelsThemes = 0xC8, //MHW1 channels and themes information section
+ TableIdMHW2Titles = 0xE6 //MHW2 titles information section
+
+};
+
+
enum DescriptorTagExt {
DishRatingDescriptorTag = 0x89,
+ SkyOTVDescriptorTag = 0x90,
DishShortEventDescriptorTag = 0x91,
DishExtendedEventDescriptorTag = 0x92,
DishSeriesDescriptorTag = 0x96,
+ MHW1DescriptorTag = 0xC1,
+ MHW1_2DescriptorTag = 0xC2,
+ FreeviewDescriptorTag = 0xD1,
+ PremiereOrderInfoDescriptorTag = 0xF0,
+ PremiereRatingInfoDescriptorTag = 0xF1,
};
// typedef InheritEnum< DescriptorTagExt, SI::DescriptorTag > ExtendedDescriptorTag;
@@ -24,7 +51,7 @@ extern bool SystemCharacterTableIsSingleByte;*/
class cEIT2:public SI::EIT
{
public:
- cEIT2(cSchedules * Schedules, int Source, u_char Tid, const u_char * Data,
+ cEIT2(cChannels* Channels, cSchedules * Schedules, int Source, u_char Tid, const u_char * Data,
EFormat format, bool isEITPid = false,
bool OnlyRunningStatus = false);
cEIT2 (cSchedule * Schedule, EFormat format);
@@ -35,7 +62,7 @@ public:
private:
void ProcessEventDescriptors(bool ExternalData, int Source, u_char Tid,
const SI::EIT::Event* SiEitEvent, cEvent* pEvent,
- cSchedules* Schedules, cChannel* channel);
+ cSchedules* Schedules, const tChannelID& channelID);
private:
bool Empty;
@@ -44,10 +71,10 @@ private:
bool OnlyRunningStatus;
time_t SegmentStart;
time_t SegmentEnd;
+ cChannels* Channels;
cSchedules* Schedules;
EFormat Format;
- cChannel* channel;
-
+ const cChannel* channel;
};
} //end namespace SI
diff --git a/epghandler.c b/epghandler.c
index 4b67fe3..1e2db9f 100644
--- a/epghandler.c
+++ b/epghandler.c
@@ -16,10 +16,15 @@
using namespace util;
+
cEEpgHandler::cEEpgHandler() {
LogD(4, prep("cEEpgHandler()"));
equivHandler = new cEquivHandler();
modified = false;
+ charsetFixer = new cCharsetFixer();
+ schedule = NULL;
+ searchDuplicates = true;
+
}
cEEpgHandler::~cEEpgHandler() {
@@ -27,14 +32,18 @@ cEEpgHandler::~cEEpgHandler() {
equivHandler = NULL;
}
+
bool cEEpgHandler::HandleEitEvent(cSchedule* Schedule,
const SI::EIT::Event* EitEvent, uchar TableID, uchar Version) {
+ schedule = Schedule;
//LogD(1, prep("HandleEitEvent"));
//DISH NID 0x1001 to 0x100B BEV 0x100 and 0x101
- int nid = Schedule->ChannelID().Nid();
- if ((nid >= 0x1001 && nid <= 0x100B) || nid == 0x101 || nid == 0x100) {
+ int nid = schedule->ChannelID().Nid();
+ if ((nid >= 0x1001 && nid <= 0x100B) || nid == 0x101 || nid == 0x100 || nid == 0x233A) {
//Set the Format for Eit events so that the new lines are not erased with FixEpgBugs
- EFormat Format = DISH_BEV;
+ EFormat Format;
+ if (nid == 0x233A) Format = FREEVIEW;
+ else Format = DISH_BEV;
SI::cEIT2 eit2(Schedule, Format);
eit2.ProcessEitEvent(Schedule, EitEvent, TableID, Version);
@@ -55,28 +64,22 @@ bool cEEpgHandler::HandleEitEvent(cSchedule* Schedule,
}
modified = false;
- //VDR creates new event if the EitEvent StartTime is different than EEPG time so
- //the EEPG event has to be deleted but the data should be kept
- const cEvent* ev = Schedule->GetEvent(EitEvent->getEventId(),EitEvent->getStartTime());
+ //VDR creates new event if the EitEvent StartTime is different than EEPG time so
+ //the EPG event has to be deleted but the data should be kept
+ const cEvent* ev = schedule->GetEvent(EitEvent->getEventId(),EitEvent->getStartTime());
+ searchDuplicates = !ev; //if the event exist with a same start time, it is handled by SetShortText/SetDescription
if (!ev){
- ev = Schedule->GetEvent(EitEvent->getEventId());
- if (ev && ((ev->StartTime()>EitEvent->getStartTime() && ev->StartTime()<=EitEvent->getStartTime()+EitEvent->getDuration())
- || (EitEvent->getStartTime() > ev->StartTime() && EitEvent->getStartTime() <= ev->EndTime()))) {
- LogD(0, prep("!!!Deleting Event id:%d title:%s start_time:%d new_start_time:%d duration:%d new_duration:%d"), ev->EventID(), ev->Title(), ev->StartTime(), EitEvent->getStartTime(), ev->Duration(), EitEvent->getDuration());
-
- if (ev->Description() && strcmp(ev->Description(),"") != 0)
- origDescription = ev->Description();
- if (ev->ShortText() && strcmp(ev->ShortText(),"") != 0)
- origShortText = ev->ShortText();
- Schedule->DelEvent((cEvent *) ev);
-// Schedule->DropOutdated(ev->StartTime()-1,ev->EndTime()+1,ev->TableID()-1,ev->Version());
- LogD(0, prep("!!!End Deleting Event"));
- //TODO equivalent channels !!!
+ ev = schedule->GetEvent(EitEvent->getEventId());
+ // remove shifted duplicates with same ID
+ if (ev && ((ev->StartTime()>EitEvent->getStartTime() && ev->StartTime() < EitEvent->getStartTime()+EitEvent->getDuration())
+ || (EitEvent->getStartTime() > ev->StartTime() && EitEvent->getStartTime() < ev->EndTime()))) {
+ LogD(0, prep("!!!Deleting Event id:%d title:%s start_time:%d new_start_time:%d duration:%d new_duration:%d"),
+ ev->EventID(), ev->Title(), ev->StartTime(), EitEvent->getStartTime(), ev->Duration(), EitEvent->getDuration());
+ RemoveEvent((cEvent*)ev);
+ searchDuplicates = false;
}
}
-
-
return false;
// return true;
}
@@ -86,13 +89,53 @@ bool cEEpgHandler::SetEventID(cEvent* Event, tEventID EventID) {
return true;
}
+void cEEpgHandler::RemoveEvent(cEvent* ev)
+{
+ if (ev->Description() && strcmp(ev->Description(), "") != 0)
+ origDescription = ev->Description();
+
+ if (ev->ShortText() && strcmp(ev->ShortText(), "") != 0)
+ origShortText = ev->ShortText();
+
+ LogD(4, prep("!!!Deleting Event id:%d title:%s start_time:%d duration:%d"),
+ ev->EventID(), ev->Title(), ev->StartTime(), ev->Duration());
+ schedule->DelEvent((ev)); //The equivalents should be handled on adding equivalent event.
+}
+
+//Find duplicate events by title / time
+//Sometimes same events overlap and have different EventID
+void cEEpgHandler::FindDuplicate(cEvent* Event, const char* newTitle)
+{
+ if (!newTitle || !searchDuplicates) return;
+
+ for (const cEvent *ev = schedule->Events()->First(); ev; ev = schedule->Events()->Next(ev)) {
+ //assume that events are already sorted.
+ if (ev->StartTime() > Event->EndTime()) break;
+ if (ev->Title() && strcasecmp(ev->Title(), newTitle) == 0
+ && ((Event->StartTime() > ev->StartTime() && Event->StartTime() < ev->EndTime())
+ || (ev->StartTime() > Event->StartTime() && ev->StartTime() < Event->EndTime()))){
+
+ LogD(0, prep("!!!Deleting Event id o:%d n:%d; title o:%s n:%s; start_time o:%d n:%d; duration o:%d n:%d"),
+ ev->EventID(), Event->EventID(), ev->Title(), newTitle, ev->StartTime(), Event->StartTime(), ev->Duration(), Event->Duration());
+ RemoveEvent((cEvent*)ev);
+ break;
+ }
+ }
+}
+
bool cEEpgHandler::SetTitle(cEvent* Event, const char* Title) {
LogD(3, prep("Event id:%d title:%s new title:%s"), Event->EventID(), Event->Title(), Title);
- if (!Event->Title() || (Title && (!strcmp(Event->Title(),"") || (strcmp(Title,"") && strcmp(Event->Title(),Title))))) {
+ const char* title = charsetFixer->FixCharset(Title);
+
+ //Sometimes same events overlap and have different EventID
+ //Find/Remove duplicates with same title/time
+ FindDuplicate(Event, title);
+
+ if (!Event->Title() || (title && (!strcmp(Event->Title(),"") || (strcmp(Title,"") && strcmp(Event->Title(),title))))) {
//LogD(0, prep("Event id:%d title:%s new title:%s"), Event->EventID(), Event->Title(), Title);
modified = true;
- Event->SetTitle(Title);
+ Event->SetTitle(title);
}
return true;
}
@@ -107,8 +150,10 @@ bool cEEpgHandler::SetShortText(cEvent* Event, const char* ShortText) {
origShortText.clear();
}
+ const char* shText = charsetFixer->FixCharset(ShortText);
+
//if (!Event->ShortText() || ShortText && (!strcmp(Event->ShortText(),"") || (strcmp(ShortText,"") && strcmp(Event->ShortText(),ShortText))))
- Event->SetShortText(ShortText);
+ Event->SetShortText(shText);
return true;
}
@@ -119,13 +164,15 @@ bool cEEpgHandler::SetDescription(cEvent* Event, const char* Description) {
origDescription = Event->Description();
else
origDescription.clear();
-
+
+ const char* desc = charsetFixer->FixCharset(Description);
+
//Based on asumption that SetDescription is always called after SetTitle
- if (!modified && Description && (!Event->Description() || strcmp(Event->Description(),Description) ))
+ if (!modified && desc && (!Event->Description() || strcmp(Event->Description(),desc) ))
modified = true;
//if (!Event->Description() || Description && (!strcmp(Event->Description(),"") || (strcmp(Description,"") && strcmp(Event->Description(),Description))))
- Event->SetDescription(Description);
+ Event->SetDescription(desc);
return true;
}
@@ -154,24 +201,51 @@ bool cEEpgHandler::SetVps(cEvent* Event, time_t Vps) {
return true;
}
+string cEEpgHandler::ExtractAttribute(const char* name)
+{
+ string attribute;
+ size_t apos = origDescription.find(name);
+ if (apos != string::npos) {
+ apos += strlen(name);
+ size_t npos = origDescription.find('\n', apos);
+ attribute = origDescription.substr(apos, npos - apos);
+ //LogD(0, prep("ExtractAttribute attribute:%s, apos:%i, pos:%i"),attribute.c_str(), catpos, pos);
+ }
+ return attribute;
+}
+
bool cEEpgHandler::HandleEvent(cEvent* Event) {
LogD(3, prep("HandleEvent st:%s ost:%s desc:%s odesc:%s"),Event->ShortText(),origShortText.c_str(),Event->Description(),origDescription.c_str());
-
//After FixEpgBugs of cEvent set the original Short Text if empty
if (!Event->ShortText() || !strcmp(Event->ShortText(),""))
Event->SetShortText(origShortText.c_str());
- if ((!Event->Description() && !origDescription.empty()) || (Event->Description() && !origDescription.empty() && origDescription.find(Event->Description()) != string::npos) ) {
+ //Handle the Category and Genre, and optionally future tags
+ if (!origDescription.empty() &&
+ (!Event->Description() ||
+ (Event->Description() && origDescription.find(Event->Description()) != string::npos))) {
Event->SetDescription(origDescription.c_str());
+ } else if (!origDescription.empty() && Event->Description()) {
+
+ string category = ExtractAttribute(CATEGORY);
+ string genre = ExtractAttribute(GENRE);
+
+ string desc = Event->Description() ? Event->Description() : "";
+ if (!category.empty()) desc += '\n' + string(CATEGORY) + category;
+ if (!genre.empty()) desc += '\n' + string(GENRE) + genre;
+ Event->SetDescription (desc.c_str());
+
}
if (equivHandler->getEquiChanMap().count(*Event->ChannelID().ToString()) <= 0)
return true;
- //if (modified)
+ if (modified)
equivHandler->updateEquivalent(Event->ChannelID(), Event);
+ //Release the schedule
+ schedule = NULL;
//TODO just to see the difference
//else if (!origDescription.empty() && !origDescription.compare(Event->Description())) {
// origDescription.append(" | EIT: ");
@@ -190,6 +264,19 @@ bool cEEpgHandler::SortSchedule(cSchedule* Schedule) {
return true;
}
+bool cEEpgHandler::FixEpgBugs(cEvent* Event)
+{
+ //to see which channels have bugs - disable fixing with true
+ return false;
+}
+
+bool cEEpgHandler::IgnoreChannel(const cChannel* Channel)
+{
+ charsetFixer->InitCharsets(Channel);
+
+ return false;
+}
+
bool cEEpgHandler::DropOutdated(cSchedule* Schedule, time_t SegmentStart,
time_t SegmentEnd, uchar TableID, uchar Version) {
return false;
diff --git a/epghandler.h b/epghandler.h
index 003fd32..4a08fcf 100644
--- a/epghandler.h
+++ b/epghandler.h
@@ -13,12 +13,15 @@
#include <string>
class cEquivHandler;
+namespace util {
+class cCharsetFixer;
+}
class cEEpgHandler : public cEpgHandler {
public:
cEEpgHandler();
virtual ~cEEpgHandler();
- virtual bool IgnoreChannel(const cChannel *Channel) { return false; }
+ virtual bool IgnoreChannel(const cChannel *Channel);
virtual bool HandleEitEvent(cSchedule *Schedule, const SI::EIT::Event *EitEvent, uchar TableID, uchar Version);
virtual bool SetEventID(cEvent *Event, tEventID EventID);
virtual bool SetTitle(cEvent *Event, const char *Title);
@@ -29,19 +32,29 @@ public:
virtual bool SetStartTime(cEvent *Event, time_t StartTime);
virtual bool SetDuration(cEvent *Event, int Duration);
virtual bool SetVps(cEvent *Event, time_t Vps);
- virtual bool FixEpgBugs(cEvent *Event) { return false; }
+ virtual bool FixEpgBugs(cEvent *Event);
virtual bool HandleEvent(cEvent *Event);
virtual bool SortSchedule(cSchedule *Schedule);
virtual bool DropOutdated(cSchedule *Schedule, time_t SegmentStart, time_t SegmentEnd, uchar TableID, uchar Version);
// bool ParseEitEvent(cSchedule *Schedule, const SI::EIT::Event *EitEvent, uchar TableID, uchar Version);
+private:
+ std::string ExtractAttribute(const char* attr);
+ void FindDuplicate(cEvent* Event, const char* newTitle);
+ /*
+ * Extract the date from duplicate event and remove it
+ */
+ void RemoveEvent(cEvent* ev);
private:
std::string origShortText;
std::string origDescription;
cEquivHandler* equivHandler;
+ util::cCharsetFixer* charsetFixer;
+ cSchedule* schedule;
static const int _LONG_EVENT_HOURS = 10;
bool modified;
+ bool searchDuplicates;
};
#endif /*APIVERSNUM > 10725*/
diff --git a/equivhandler.c b/equivhandler.c
index 281d2f3..75007ec 100644
--- a/equivhandler.c
+++ b/equivhandler.c
@@ -24,7 +24,6 @@ cEquivHandler::cEquivHandler()
cEquivHandler::~cEquivHandler()
{
- // TODO Auto-generated destructor stub
}
void cEquivHandler::loadEquivalentChannelMap (void)
@@ -55,62 +54,72 @@ void cEquivHandler::loadEquivalentChannelMap (void)
char origChanID[256];
char equiChanID[256];
char source[256];
- int nid = 0;
- int tid = 0;
- int sid = 0;
- int rid = 0;
+ int nid, tid, sid, 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;
- 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
+ //skip empty and commented lines
+ if (isempty (Line) || Line[0] == '#' || Line[0] == ';') continue;
+ //skip invalid line
+ if (sscanf (Line, "%[^ ] %[^ ] %[^\n]\n", origChanID, equiChanID, source) != 3) continue;
+
+ nid = 0;
+ tid = 0;
+ sid = 0;
+ rid = 0;
+ //skip invalid id formats
+ if ((sscanf (origChanID, "%[^-]-%i -%i -%i ", source, &nid, &tid, &sid) != 4)
+ && (sscanf (equiChanID, "%[^-]-%i -%i -%i ", source, &nid, &tid, &sid) != 4))
+ continue;
+
+ 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;
+#if APIVERSNUM >= 20300
+ LOCK_CHANNELS_READ;
+ const cChannel *OriginalChannel = Channels->GetByChannelID(OriginalChID, false);
+#else
+ cChannel *OriginalChannel = Channels.GetByChannelID (OriginalChID, false);
+#endif
+ 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);
+ 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);
+#if APIVERSNUM >= 20300
+ const cChannel *EquivChannel = Channels->GetByChannelID(EquivChID, false);
+#else
+ cChannel *EquivChannel = Channels.GetByChannelID (EquivChID, false);
+#endif
+ if (!EquivChannel) {
+ LogI(0, prep("Warning, not found equivalent channel \'%s\' in channels.conf"), equiChanID);
+ continue;
+ }
+
+ //check if channel is already added
+ ret = equiChanMap.equal_range(*OriginalChID.ToString());
+ for (it=ret.first; it!=ret.second; ++it)
+ if ((*it).second == *OriginalChID.ToString()) {
+ found = true;
+ break;
+ }
+ if (found) continue;
+
+ 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());
+ }
} //while
fclose (File);
equiChanFileTime = st.st_mtim.tv_nsec;
@@ -130,7 +139,7 @@ void cEquivHandler::updateEquivalent(cSchedules * Schedules, tChannelID channelI
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);
+ const cChannel *equChannel = GetChannelByID (equChannelID, false);
if (equChannel) {
LogD(2, prep("found Equivalent channel %s"), *equChannelID.ToString());
cSchedule *pSchedule = (cSchedule *) Schedules->GetSchedule (equChannel, true);
@@ -192,14 +201,18 @@ void cEquivHandler::sortEquivalents(tChannelID channelID, cSchedules* Schedules)
{
LogD(3, prep("equivalent channel exists"));
tChannelID equChannelID(tChannelID::FromString((*it).second.c_str()));
- cChannel* pChannel = GetChannelByID(equChannelID, false);
+ const 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();
+#if APIVERSNUM >= 20300
+ pSchedule->SetModified();
+#else
Schedules->SetModified(pSchedule);
+#endif
}
}
}
diff --git a/extra/en-themes/mhw1_fr.tr b/extra/en-themes/mhw1_fr.tr
new file mode 100644
index 0000000..cef2cb4
--- /dev/null
+++ b/extra/en-themes/mhw1_fr.tr
@@ -0,0 +1,81 @@
+#
+# Translation of MHW1 Fr themes into En
+# Fromat:
+# Original Key=Translated
+
+#. /Categories
+DIVERTISSEMENT=Entertainment
+DOCUMENTAIRE=Documentary
+EVENEMENT=Event
+FILM=Movie
+INFO/METEO=News/Wather
+JEUNESSE=Youth
+MAGAZINE=Magazine
+MUSIQUE=Music
+SERIE=Series
+SPORT=Sports
+
+#. /Genres
+ACTION=Action
+ANIMATION=Animation
+ARTE=Art
+ATHLETISME=Athletics
+BASKETBALL=Basketball
+CARRE ROSE=
+CHARME=
+CINEMA=Cinema
+CLASSIC-CONTEMP=Classic-Contemp
+CLIPS=Clips
+COURSE HIPPIQUE=Horse Racing
+COURT METRAGE=Short Film
+CULTURE=Culture
+CYCLISME=Cycling
+DANSE=Dance
+DE COMBAT=Combat
+DE GLISSE=Gliding
+DEBAT=Debate
+DECOUVERTE=Discovery
+DESSINS -ANIMES=
+ECONOMIE=Economy
+EDUCATION=Educational
+EROTIQUE=Erotic
+EVASION=
+FOOTBALL=Football
+FRISSON=Thriller
+FUN=Fun
+FUNK-SOUL=Funk / Soul
+GOLF=Golf
+GRAND PRIX F1=Formula 1
+HISTOIRE=History
+HORREUR=Horror
+INFO=News
+INFORMATION=Information
+JAZZ-BLUES=Jazz / Blues
+JEU=Games
+MECANIQUE=Mechanical
+METEO=Weather
+MODE=Fashion
+MUSIQ. DU MONDE=World Music
+NATURE=Nature
+OPERA=Opera
+PASSION=Passion
+POLITIQUE=Politics
+PORTRAIT=Portrait
+RAP-GROOVE=Rap-Groove
+RIRES=Laughter
+ROCK-POP=Rock / Pop
+RUGBY=Rugby
+SC. & TECH=Science & Technology
+SC. & TECH.=Science & Technology
+SC.FICTION=Sci-Fi
+SCIENCE FICTION=Sci-Fi
+SERVICE=Service
+SKI=Ski
+SOCIETE=Society
+SPECTACLE=Show
+TECHNO-DANCE=Techno / Dance
+TENDRESSE=
+TENNIS=Tennis
+THEATRE=Theatre
+TV ACHAT=Teleshopping
+VARIETES=Variety
diff --git a/extra/en-themes/mhw2_es.tr b/extra/en-themes/mhw2_es.tr
new file mode 100644
index 0000000..fe31a73
--- /dev/null
+++ b/extra/en-themes/mhw2_es.tr
@@ -0,0 +1,103 @@
+#
+# Translation of MHW2 Es themes into En
+# Fromat:
+# Original Key=Translated
+
+#. /Categories
+CINE=Movie
+CULTURAL/EDUCAT.=Cultural/Educat.
+DEPORTES=Sports
+DOCUMENTALES=Documentary
+ENTRETENIMIENTO=Entertainment
+INFANTIL=Children
+INFORMACIÓ=Information
+MÚSIC=Music
+OCIO Y AFICIONES=Leisure & Hobbies
+OTROS=Other
+SERIES=Series
+
+#. /Genres
+ACCIÓN=Action
+ACTUALIDAD=News
+ADULTO=Adult
+ANIMACIÓN=Animation
+ARTE Y CULTURA=Art & Culture
+ATLETISMO=Athletics
+AVENTURAS=Adventure
+BALONCESTO=Basketball
+BALONMANO=Handball
+BELLEZA=Beauty
+BIOGRAFÍA=Biography
+BRICOLAJE=DIY
+CAZA Y PESCA=Hunting & Fishing
+CIENCIA FICCIÓN=Sci-Fi
+CIENCIA Y TECNOLOGÍA=Science & Technology
+CLÁSICA=Classic
+COCINA=Cooking
+COMEDIA=Comedy
+COMEDIA ROMÁNT.=Romantic Comedy
+CONCIERTO=Concert
+CONCURSO=Contest
+CORAZÓN / SOCIEDAD=
+CORTOMETRAJE=Short Film
+DANCE / ELECTRÓNICA=Dance / Electornic
+DANZA / BALLET=Dance / Ballet
+DEBATE=Debate
+DECORACIÓN=Decor
+DEPORTE=Sport
+DEPORTES ACUÁTICOS=Watersports
+DEPORTES DE INVIERNO=Winter Sports
+DIBUJOS ANIMADOS=Cartoons
+DRAMA=Drama
+ECONOMÍA=Economy
+EDUCATIVO=Educational
+ENTREVISTA=Interview
+ESOTERISMO=
+FOOTBALL=Football
+FORMACIÓN=Training
+FÚTBOL=Football
+FÚTBOL AMERICANO=American Football
+HISTORIA=History
+HISTÓRICO=Historical
+HUMOR=Humor
+IDIOMAS=Languages
+INFORMATIVO=Information
+JAZZ / BLUES=Jazz / Blues
+JUEGOS=Games
+JUVENIL=Youth
+LISTAS=Lists
+LITERATURA=Literature
+MAGACÍN=Magazine
+MAGACÍN DEPORTIVO=Sports Magazine
+MELODRAMA=Melodrama
+METEOROLOGÍA=Weather
+MINISERIE=Mini series
+MODA=Fashion
+MOTOR=Moto
+MUSICAL=Musical
+MÚSICA=Music
+NATURALEZA=Nature
+NOCHE=Nights
+OESTE=Western
+POLICÍACA=Detective
+POLICÍACO=Detective
+PREESCOLAR=Preschool
+RELIGIÓN=Religious
+REPORTAJE=Reportage
+REVISTA CULTURAL=Culture Magazine
+ROCK / POP=Rock / Pop
+SALUD Y BIENESTAR=Health & Wellness
+SOCIEDAD=Society
+SUSPENSE=Thriller
+TECNOLOGÍA=Technology
+TELE REALIDAD=Reality TV
+TELEFILME=Telefilm
+TELENOVELA=Soap
+TELEVENTA=Teleshopping
+TENDENCIAS=Trends
+TERROR=Horror
+TOROS=Bulls
+TURISMO=Travel
+VIAJES / EXPEDICIONES=Travel / Expeditions
+VIDEOCLIPS=Clips
+ÓPERA=Opera \ No newline at end of file
diff --git a/extra/en-themes/sky_it.themes b/extra/en-themes/sky_it.themes
new file mode 100644
index 0000000..198c79a
--- /dev/null
+++ b/extra/en-themes/sky_it.themes
@@ -0,0 +1,256 @@
+0x00=No Category
+0x01=
+0x02=
+0x03=
+0x04=
+0x05=
+0x06=
+0x07=
+0x08=
+0x09=
+0x0a=
+0x0b=
+0x0c=
+0x0d=
+0x0e=
+0x0f=
+0x10=
+0x11=
+0x12=
+0x13=
+0x14=
+0x15=
+0x16=
+0x17=
+0x18=
+0x19=
+0x1a=
+0x1b=
+0x1c=
+0x1d=
+0x1e=
+0x1f=
+0x20=Entertainment
+0x21=Entertainment - Fiction
+0x22=Entertainment - Sit Com
+0x23=Entertainment - Show
+0x24=Entertainment - Telefilm
+0x25=Entertainment - Soap Opera
+0x26=Entertainment - Telenovela
+0x27=Entertainment - Sci-Fi
+0x28=Entertainment - Animation
+0x29=Entertainment - Detective
+0x2a=Entertainment - Drama
+0x2b=Entertainment - Romance
+0x2c=Entertainment - Mini series
+0x2d=Entertainment - Spectacle
+0x2e=Entertainment - Quiz
+0x2f=Entertainment - Talk Show
+0x30=Entertainment - Variety
+0x31=Entertainment - Festival
+0x32=Entertainment - Teater
+0x33=Entertainment - Game
+0x34=
+0x35=
+0x36=
+0x37=
+0x38=
+0x39=
+0x3a=
+0x3b=
+0x3c=
+0x3d=
+0x3e=
+0x3f=
+0x40=Sports
+0x41=Sports - Football
+0x42=Sports - Tennis
+0x43=Sports - Motor Sport
+0x44=Sports - Other
+0x45=Sports - Baseball
+0x46=Sports - Cycling
+0x47=Sports - Rugby
+0x48=Sports - Basketball
+0x49=Sports - Boxing
+0x4a=Sports - Athletics
+0x4b=Sports - American Football
+0x4c=Sports - Ice Hockey
+0x4d=Sports - Ski
+0x4e=Sports - Equestrian
+0x4f=Sports - Golf
+0x50=Sports - Watersports
+0x51=Sports - Wrestling
+0x52=Sports - Handball
+0x53=Sports - Volleyball
+0x54=Sports - Poker
+0x55=Sports - Sailing
+0x56=Sports - Winter Sports
+0x57=
+0x58=
+0x59=
+0x5a=
+0x5b=
+0x5c=
+0x5d=
+0x5e=
+0x5f=
+0x60=Movie
+0x61=Movie - Drama
+0x62=Movie - Comedy
+0x63=Movie - Romance
+0x64=Movie - Action
+0x65=Movie - Sci-Fi
+0x66=Movie - Western
+0x67=Movie - Comic
+0x68=Movie - Fantasy
+0x69=Movie - Adventure
+0x6a=Movie - Crime
+0x6b=Movie - War
+0x6c=Movie - Horror
+0x6d=Movie - Animation
+0x6e=Movie - Thriller
+0x6f=Movie - Musical
+0x70=Movie - Short
+0x71=Movie - Short film
+0x72=Movie - Erotic
+0x73=
+0x74=
+0x75=
+0x76=
+0x77=
+0x78=
+0x79=
+0x7a=
+0x7b=
+0x7c=
+0x7d=
+0x7e=
+0x7f=
+0x80=World & Trends
+0x81=World & Trends - Nature
+0x82=World & Trends - Art & Culture
+0x83=World & Trends - Lifestyle
+0x84=World & Trends - Travel
+0x85=World & Trends - Documentary
+0x86=World & Trends - Society
+0x87=World & Trends - Science
+0x88=World & Trends - History
+0x89=World & Trends - Sport
+0x8a=World & Trends - Fishing
+0x8b=World & Trends - People
+0x8c=World & Trends - Cinema
+0x8d=World & Trends - Music
+0x8e=World & Trends - Hobby
+0x8f=World & Trends - Hunting
+0x90=World & Trends - Reportage
+0x91=World & Trends - Magazine
+0x92=World & Trends - Culture Magazine
+0x93=World & Trends - Science Magazine
+0x94=World & Trends - Politics
+0x95=World & Trends - Cinema Magazine
+0x96=World & Trends - Sport Magazine
+0x97=World & Trends - Actuality
+0x98=World & Trends - Fashion
+0x99=World & Trends - Economy
+0x9a=World & Trends - Hunting & Fishing Magazine
+0x9b=World & Trends - Travel Magazine
+0x9c=World & Trends - Nature Magazine
+0x9d=World & Trends - Music Magazine
+0x9e=World & Trends - Religion
+0x9f=World & Trends - Teleshopping
+0xa0=Information
+0xa1=Information - News
+0xa2=Information - Sport
+0xa3=Information - Economy
+0xa4=
+0xa5=Information - Weather
+0xa6=
+0xa7=
+0xa8=
+0xa9=
+0xaa=
+0xab=
+0xac=
+0xad=
+0xae=
+0xaf=
+0xb0=
+0xb1=
+0xb2=
+0xb3=
+0xb4=
+0xb5=
+0xb6=
+0xb7=
+0xb8=
+0xb9=
+0xba=
+0xbb=
+0xbc=
+0xbd=
+0xbe=
+0xbf=
+0xc0=Children & Music
+0xc1=Children & Music - Kids
+0xc2=Children & Music - Children
+0xc3=Children & Music - Cartoons
+0xc4=Children & Music - Music
+0xc5=Children & Music - Animation Movie
+0xc6=Children & Music - Movie
+0xc7=Children & Music - Telefilm
+0xc8=Children & Music - Magazine
+0xc9=Children & Music - Games
+0xca=
+0xcb=Children & Music - Chamber Music
+0xcc=
+0xcd=
+0xce=
+0xcf=
+0xd0=
+0xd1=Children & Music - Concert
+0xd2=
+0xd3=
+0xd4=Children & Music - Dance
+0xd5=Children & Music - Videoclip
+0xd6=
+0xd7=
+0xd8=
+0xd9=
+0xda=
+0xdb=
+0xdc=
+0xdd=
+0xde=
+0xdf=
+0xe0=Other
+0xe1=Other - Educational
+0xe2=Other - Regional
+0xe3=Other - Shopping
+0xe4=Other - Other
+0xe5=Other - Start & End Transmission
+0xe6=Other - Special Events
+0xe7=Other - Adult Movie
+0xe8=
+0xe9=
+0xea=
+0xeb=
+0xec=
+0xed=
+0xee=
+0xef=
+0xf0=
+0xf1=
+0xf2=
+0xf3=
+0xf4=
+0xf5=
+0xf6=
+0xf7=
+0xf8=
+0xf9=
+0xfa=
+0xfb=
+0xfc=
+0xfd=
+0xfe=
+0xff=
diff --git a/po/mk_MK.po b/po/mk_MK.po
new file mode 100644
index 0000000..6b2ef2b
--- /dev/null
+++ b/po/mk_MK.po
@@ -0,0 +1,77 @@
+# Macedonian translations for vdr-eepg package.
+# Copyright (C) 2012 THE vdr-eepg'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the VDR package.
+# Dimitar Petrovski <dimeptr@gmail.com>, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: vdr-eepg 0.0.6pre\n"
+"Report-Msgid-Bugs-To: <see README>\n"
+"POT-Creation-Date: 2012-11-20 23:13+0100\n"
+"PO-Revision-Date: 2012-10-29 13:44+0100\n"
+"Last-Translator: Dimitar Petrovski <dimeptr@gmail.com>\n"
+"Language-Team: Macedonian\n"
+"Language: mk\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "Parses Extended EPG data"
+msgstr "Анализира Опширни ЕПГ податоци"
+
+msgid "PremiereEPG"
+msgstr "Премиер ЕПГ"
+
+msgid "off"
+msgstr "исклучено"
+
+msgid "Tag option events"
+msgstr "Таг за опцоини настани"
+
+msgid "Show order information"
+msgstr "Прикажи информации за нарачка"
+
+msgid "Show rating information"
+msgstr "Прикажи информации за рејтинг"
+
+msgid "Fix EPG data"
+msgstr "Поправи ЕПГ податоци"
+
+msgid "General"
+msgstr "Општо"
+
+msgid "Display summary message"
+msgstr "Прикажи сумарна порака"
+
+msgid "Replace empty Short Text with Category - Genre"
+msgstr "Замени празен Краток Текст со Категорија - Жанр"
+
+msgid "Try to fix CharSet for events"
+msgstr "Пробај да го поправиш сетот на карактери за настаните"
+
+msgid "Level of logging verbosity"
+msgstr "Ниво на логирање"
+
+msgid "Process EIT info with EEPG"
+msgstr "Процесирај ЕИТ информации со ЕЕПГ"
+
+msgid "Ordernumber"
+msgstr "Бр. на нарачка"
+
+msgid "Price"
+msgstr "Цена"
+
+msgid "Ordering"
+msgstr "Нарачка"
+
+msgid "SMS"
+msgstr "СМС"
+
+msgid "WWW"
+msgstr "WWW"
+
+msgid "Rating"
+msgstr "Рејтинг"
+
+msgid "years"
+msgstr "години"
diff --git a/setupeepg.c b/setupeepg.c
index c0dff6a..c6056d8 100644
--- a/setupeepg.c
+++ b/setupeepg.c
@@ -22,6 +22,9 @@ cSetupEEPG::cSetupEEPG (void)
FixEpg = 0;
DisplayMessage = 1;
ProcessEIT = 0;
+ ReplaceEmptyShText = 0;
+ FixCharset = 0;
+
#ifdef DEBUG
LogLevel = 0;
#endif
diff --git a/setupeepg.h b/setupeepg.h
index 0db20d1..ed0f04e 100644
--- a/setupeepg.h
+++ b/setupeepg.h
@@ -18,6 +18,8 @@ public:
int FixEpg;
int DisplayMessage;
int ProcessEIT;
+ int ReplaceEmptyShText;
+ int FixCharset;
#ifdef DEBUG
int LogLevel;
#endif
diff --git a/util.c b/util.c
index 4fc0c48..b41faf8 100644
--- a/util.c
+++ b/util.c
@@ -7,6 +7,7 @@
#include "util.h"
#include "log.h"
#include "equivhandler.h"
+#include "setupeepg.h"
#include <vdr/channels.h>
#include <vdr/thread.h>
#include <vdr/epg.h>
@@ -25,17 +26,27 @@ int YesterdayEpochUTC;
struct hufftab *tables[2][128];
int table_size[2][128];
+map<string,string> tableDict;
cEquivHandler* EquivHandler;
-cChannel *GetChannelByID(tChannelID & channelID, bool searchOtherPos)
+const cChannel *GetChannelByID(const tChannelID & channelID, bool searchOtherPos)
{
- cChannel *VC = Channels.GetByChannelID(channelID, true);
+#if APIVERSNUM >= 20300
+ LOCK_CHANNELS_READ;
+ const cChannel *VC = Channels->GetByChannelID(channelID, true);
+#else
+ const cChannel *VC = Channels.GetByChannelID(channelID, true);
+#endif
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);
+ tChannelID chID = tChannelID(AvailableSources[i], channelID.Nid(), channelID.Tid(), channelID.Sid());
+#if APIVERSNUM >= 20300
+ VC = Channels->GetByChannelID(chID, true);
+#else
+ VC = Channels.GetByChannelID(chID, true);
+#endif
if(VC){
//found this actually on satellite nextdoor...
break;
@@ -149,7 +160,7 @@ struct tChannelIDCompare
};
cTimeMs LastAddEventThread;
-enum { INSERT_TIMEOUT_IN_MS = 10000 };
+enum { INSERT_TIMEOUT_IN_MS = 5000 };
class cAddEventThread : public cThread
{
@@ -157,6 +168,7 @@ private:
cTimeMs LastHandleEvent;
std::map<tChannelID,cList<cEvent>*,tChannelIDCompare> *map_list;
// enum { INSERT_TIMEOUT_IN_MS = 10000 };
+ void MergeEquivalents(cEvent* dest, const cEvent* src);
protected:
virtual void Action(void);
public:
@@ -182,38 +194,55 @@ cAddEventThread::~cAddEventThread(void)
void cAddEventThread::Action(void)
{
- //LogD (0, prep("Action"));
SetPriority(19);
while (Running() && !LastHandleEvent.TimedOut()) {
std::map<tChannelID, cList<cEvent>*, tChannelIDCompare>::iterator it;
+#if APIVERSNUM >= 20300
+ LOCK_SCHEDULES_WRITE;
+ cSchedules *schedules = Schedules;
+#else
cSchedulesLock SchedulesLock(true, 10);
- cSchedules *schedules = (cSchedules *) cSchedules::Schedules(SchedulesLock);
- Lock();
+ cSchedules *schedules = (cSchedules*)(cSchedules::Schedules(SchedulesLock));
+#endif
+ Lock();
it = map_list->begin();
while (schedules && it != map_list->end()) {
cSchedule *schedule = (cSchedule *) schedules->GetSchedule(
- Channels.GetByChannelID((*it).first), true);
+ GetChannelByID((*it).first, false), true);
while (((*it).second->First()) != NULL) {
cEvent* event = (*it).second->First();
- cEvent *pEqvEvent = (cEvent *) schedule->GetEvent (event->EventID(), event->StartTime());
- if (pEqvEvent){
-// LogD (0, prep("schedule->DelEvent(event) size:%d"), (*it).second->Count());
- (*it).second->Del(event);
-// schedule->DelEvent(pEqvEvent);
- } else {
-
- (*it).second->Del(event, false);
- EpgHandlers.DropOutdated(schedule, event->StartTime(), event->EndTime(), event->TableID(),
- event->Version());
- schedule->AddEvent(event);
+ cEvent *pEqvEvent = (cEvent *) schedule->GetEvent (event->EventID(), event->StartTime());
+ if (pEqvEvent){
+ (*it).second->Del(event);
+ } else {
+
+ (*it).second->Del(event, false);
+
+ for (const cEvent *ev = schedule->Events()->First(); ev; ev = schedule->Events()->Next(ev)) {
+ if (ev->StartTime() > event->EndTime()) {
+ break;
+ }
+ if (ev && (ev->EventID() == event->EventID() || (event->Title() && strcasecmp(ev->Title(), event->Title()) == 0))
+ && ((event->StartTime() >= ev->StartTime() && event->StartTime() < ev->EndTime())
+ || (ev->StartTime() >= event->StartTime() && ev->StartTime() < event->EndTime()))){
+ MergeEquivalents(event, ev);
+ schedule->DelEvent((cEvent*)ev);
+ break;
+ }
+ }
+
+ event = schedule->AddEvent(event);
+ EpgHandlers.DropOutdated(schedule, event->StartTime(), event->EndTime(), event->TableID(),
+ event->Version());
+
}
}
EpgHandlers.SortSchedule(schedule);
- //sortSchedules(schedules, (*it).first);
- //schedule->Sort();
+ //sortSchedules(schedules, (*it).first);
+ //schedule->Sort();
delete (*it).second;
map_list->erase(it);
it = map_list->begin();
@@ -238,6 +267,42 @@ void cAddEventThread::AddEvent(cEvent *Event, tChannelID ChannelID)
LastHandleEvent.Set(INSERT_TIMEOUT_IN_MS);
}
+string ExtractAttributes(string text) {
+ string attribute;
+ size_t apos = 0;
+ while ((apos = text.find('\n',apos)) != string::npos) {
+ size_t npos = text.find('\n', apos);
+ string subs = text.substr(apos, npos - apos);
+ if (subs.find(": ") != string::npos)
+ attribute += subs;
+ apos = npos;
+ //LogD(0, prep("ExtractAttribute attribute:%s, apos:%i, pos:%i"),attribute.c_str(), catpos, pos);
+ }
+ return attribute;
+
+}
+
+inline void cAddEventThread::MergeEquivalents(cEvent* dest, const cEvent* src)
+{
+ if (!dest->ShortText() || !strcmp(dest->ShortText(),""))
+ dest->SetShortText(src->ShortText());
+
+ //Handle the Category and Genre, and optionally future tags
+ if (!src->Description() || !strcmp(src->Description(),""))
+ return;
+
+ if ((!dest->Description() || strstr(src->Description(),dest->Description()))) {
+ dest->SetDescription(src->Description());
+ } else if (dest->Description()) {
+
+ string desc = dest->Description() ? dest->Description() : "";
+ desc += ExtractAttributes(desc);
+ dest->SetDescription (desc.c_str());
+
+ }
+
+}
+
static cAddEventThread AddEventThread;
// ---
@@ -249,7 +314,7 @@ void AddEvent(cEvent *Event, tChannelID ChannelID)
// if (!AddEventThread.Active())
// AddEventThread.Start();
if (!AddEventThread.Active() && LastAddEventThread.TimedOut()){
- LastAddEventThread.Set(INSERT_TIMEOUT_IN_MS * 2);
+ LastAddEventThread.Set(INSERT_TIMEOUT_IN_MS * 1.5);
AddEventThread.Start();
}
@@ -376,16 +441,106 @@ void sortSchedules(cSchedules * Schedules, tChannelID channelID){
LogD(3, prep("Start sortEquivalent %s"), *channelID.ToString());
- cChannel *pChannel = GetChannelByID (channelID, false);
+ const cChannel *pChannel = GetChannelByID (channelID, false);
cSchedule *pSchedule;
if (pChannel) {
pSchedule = (cSchedule *) (Schedules->GetSchedule(pChannel, true));
pSchedule->Sort();
+#if APIVERSNUM >= 20300
+ pSchedule->SetModified();
+#else
Schedules->SetModified(pSchedule);
+#endif
}
if (EquivHandler->getEquiChanMap().count(*channelID.ToString()) > 0)
EquivHandler->sortEquivalents(channelID, Schedules);
}
+cCharsetFixer::cCharsetFixer()
+{
+ charsetOverride = getenv("VDR_CHARSET_OVERRIDE");
+ if (!charsetOverride) charsetOverride = "ISO6937";
+ initialCharset = charsetOverride;
+ fixedCharset = "";
+ conv_revert = NULL;
+ conv_to = NULL;
+
}
+cCharsetFixer::~cCharsetFixer()
+{
+}
+
+const char* cCharsetFixer::FixCharset(const char* text)
+{
+ if (!text || !conv_revert || !conv_to) return text;
+
+ //LogD(0, prep("FixCharset fixCharset:%s charsetOverride:%s text:%s"), fixCharset.c_str(), CharsetOverride, text);
+ const char* fixed = NULL;
+ if (!fixedCharset.empty()) {
+
+ if (fixedCharset != charsetOverride) {
+ //LogD(0, prep("FixCharset2 fixCharset:%s charsetOverride:%s text:%s"), fixCharset.c_str(), CharsetOverride, text);
+ fixed = conv_revert->Convert(text);
+ //LogD(0, prep("conv 1 fixed:%s"),fixed);
+ fixed = conv_to->Convert(fixed);
+ //LogD(0, prep("Fixed text:%s"), fixed);
+ }
+ }
+ if (!fixed) fixed = text;
+ return fixed;
+
+}
+
+void cCharsetFixer::InitCharsets(const cChannel* Channel)
+{
+ if (!cSetupEEPG::getInstance()->FixCharset) return;
+
+ if (strcasecmp( Channel->Provider(), "Skylink") == 0 || strcasecmp( Channel->Provider(), "UPC Direct") == 0
+ || strcasecmp( Channel->Provider(), "CYFRA +") == 0) {
+ fixedCharset = "ISO6937";
+ } else if (strcasestr( Channel->Provider(), "Polsat") != 0) {
+ fixedCharset = "ISO-8859-2";
+ } else if (Channel->Nid() == 0x01) {
+ fixedCharset = "ISO-8859-9";
+ } else {
+ fixedCharset = "";
+ }
+
+
+ if (!fixedCharset.empty()) {
+ if (conv_to)
+ delete conv_to;
+ conv_to = new cCharSetConv(fixedCharset.c_str());
+
+
+ const char* chrs;
+ if (strcasecmp( Channel->Provider(), "CYFRA +") == 0) {
+ chrs = "ISO-8859-5";
+ }else {
+ chrs = charsetOverride;
+ }
+
+ if (initialCharset != chrs) {
+ delete conv_revert;
+ conv_revert = NULL;
+ }
+ if (!conv_revert || initialCharset != chrs)
+ conv_revert = new cCharSetConv(NULL,chrs);
+
+ initialCharset = chrs;
+ }
+
+}
+
+string findThemeTr(const char* text)
+{
+ map<string,string>::iterator it;
+ string trans = text;
+ if ((it = tableDict.find(trans)) != tableDict.end())
+ trans = it->second;
+ LogD(4, prep("original:%s translated:%s map size:%d"), text, trans.c_str(), tableDict.size());
+ return trans;
+}
+
+}
diff --git a/util.h b/util.h
index 0113249..7573744 100644
--- a/util.h
+++ b/util.h
@@ -9,22 +9,30 @@
#define UTIL_H_
#include <time.h>
#include <stdlib.h>
+#include <string>
+#include <map>
class cChannel;
struct tChannelID;
class cEvent;
class cEquivHandler;
class cSchedules;
+class cCharSetConv;
#define START '\0'
#define STOP '\0'
#define ESCAPE '\1'
+
+
#define Asprintf(a, b, c...) void( asprintf(a, b, c) < 0 ? esyslog("memory allocation error - %s", b) : void() )
namespace util
{
+static const char CATEGORY[] = "Category: ";
+static const char GENRE[] = "Genre: ";
+
extern int AvailableSources[32];
extern int NumberOfAvailableSources;
@@ -53,7 +61,7 @@ extern cEquivHandler* EquivHandler;
void AddEvent(cEvent *event, tChannelID ChannelID);
-cChannel *GetChannelByID(tChannelID & channelID, bool searchOtherPos);
+const cChannel *GetChannelByID(const tChannelID & channelID, bool searchOtherPos);
time_t LocalTime2UTC(time_t t);
time_t UTC2LocalTime(time_t t);
void GetLocalTimeOffset(void);
@@ -61,6 +69,12 @@ void CleanString(unsigned char *String);
void decodeText2(const unsigned char *from, int len, char *buffer, int buffsize);
char *freesat_huffman_decode(const unsigned char *src, size_t size);
void sortSchedules(cSchedules * Schedules, tChannelID channelID);
+/**
+ * Locate the translation of a given Theme (Category, Genre) string in the translation map
+ * @param the text to search
+ * @return found translation or the source text if not found.
+ */
+std::string findThemeTr(const char*);
//struct sNode
//{
@@ -88,6 +102,25 @@ struct hufftab
extern struct hufftab *tables[2][128];
extern int table_size[2][128];
//static sNodeH* sky_tables[2];
+extern std::map<std::string,std::string> tableDict;
+
+
+class cCharsetFixer
+{
+public:
+ cCharsetFixer();
+ virtual ~cCharsetFixer();
+ const char* FixCharset(const char* text);
+ void InitCharsets(const cChannel* Channel);
+
+private:
+ cCharSetConv* conv_revert;//("UTF-8",CharsetOverride);
+ cCharSetConv* conv_to;//(fixCharset.c_str());
+ const char* charsetOverride;
+ std::string fixedCharset;
+ std::string initialCharset;
+
+};
}
#endif /* UTIL_H_ */