summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config.c43
-rw-r--r--config.h11
-rw-r--r--epgfixer.c24
-rw-r--r--epghandler.c266
-rw-r--r--epghandler.h6
-rw-r--r--regexp.c74
-rw-r--r--regexp.h1
-rw-r--r--setup_menu.c4
-rw-r--r--tools.c272
-rw-r--r--tools.h15
10 files changed, 351 insertions, 365 deletions
diff --git a/config.c b/config.c
index 9fab87b..5c6e586 100644
--- a/config.c
+++ b/config.c
@@ -5,8 +5,6 @@
*
*/
-#include <stdlib.h>
-#include <string.h>
#include "config.h"
/* Global instance */
@@ -25,44 +23,3 @@ cEpgfixerSetup::cEpgfixerSetup()
components = 0;
striphtml = 0;
}
-
-cString cEpgfixerSetup::m_ProcessedArgs;
-
-bool cEpgfixerSetup::ProcessArg(const char *Name, const char *Value)
-{
- if (SetupParse(Name, Value)) {
- m_ProcessedArgs = cString::sprintf("%s%s ", *m_ProcessedArgs ? *m_ProcessedArgs : " ", Name);
- return true;
- }
- return false;
-}
-
-bool cEpgfixerSetup::ProcessArgs(int argc, char *argv[])
-{
- return true;
-}
-
-bool cEpgfixerSetup::SetupParse(const char *Name, const char *Value)
-{
- const char *pt;
- if (*m_ProcessedArgs && NULL != (pt = strstr(m_ProcessedArgs + 1, Name)) &&
- *(pt - 1) == ' ' && *(pt + strlen(Name)) == ' ') {
- dsyslog("Skipping configuration entry %s=%s (overridden in command line)", Name, Value);
- return true;
- }
-
- if (!strcasecmp(Name, "RemoveQuotesFromShortText")) quotedshorttext = atoi(Value);
- else if (!strcasecmp(Name, "MoveDescriptionFromShortText")) blankbeforedescription = atoi(Value);
- else if (!strcasecmp(Name, "RemoveRepeatedTitleFromShortText")) repeatedtitle = atoi(Value);
- else if (!strcasecmp(Name, "RemoveDoubleQuotesFromShortText")) doublequotedshorttext = atoi(Value);
- else if (!strcasecmp(Name, "RemoveUselessFormatting")) removeformatting = atoi(Value);
- else if (!strcasecmp(Name, "MoveLongShortTextToDescription")) longshorttext = atoi(Value);
- else if (!strcasecmp(Name, "PreventEqualShortTextAndDescription")) equalshorttextanddescription = atoi(Value);
- else if (!strcasecmp(Name, "ReplaceBackticksWithSingleQuotes")) nobackticks = atoi(Value);
- else if (!strcasecmp(Name, "FixStreamComponentDescriptions")) components = atoi(Value);
- else if (!strcasecmp(Name, "StripHTMLEntities")) striphtml = atoi(Value);
- else
- return false;
-
- return true;
-}
diff --git a/config.h b/config.h
index 3650d72..670db11 100644
--- a/config.h
+++ b/config.h
@@ -8,11 +8,8 @@
#ifndef __EPGFIXER_CONFIG_H_
#define __EPGFIXER_CONFIG_H_
-#include <vdr/tools.h>
-
-class cEpgfixerSetup
+struct cEpgfixerSetup
{
-public:
int quotedshorttext;
int blankbeforedescription;
int repeatedtitle;
@@ -24,12 +21,6 @@ public:
int components;
int striphtml;
cEpgfixerSetup();
- bool SetupParse(const char *Name, const char *Value);
- bool ProcessArgs(int argc, char *argv[]);
-
-protected:
- bool ProcessArg(const char *Name, const char *Value);
- static cString m_ProcessedArgs;
};
// Global instance
diff --git a/epgfixer.c b/epgfixer.c
index 653179f..889f929 100644
--- a/epgfixer.c
+++ b/epgfixer.c
@@ -145,7 +145,29 @@ cMenuSetupPage *cPluginEpgfixer::SetupMenu(void)
bool cPluginEpgfixer::SetupParse(const char *Name, const char *Value)
{
// Parse your own setup parameters and store their values.
- return EpgfixerSetup.SetupParse(Name, Value);
+ cString m_ProcessedArgs;
+ // Parse your own setup parameters and store their values.
+ const char *pt;
+ if (*m_ProcessedArgs && NULL != (pt = strstr(m_ProcessedArgs + 1, Name)) &&
+ *(pt - 1) == ' ' && *(pt + strlen(Name)) == ' ') {
+ dsyslog("Skipping configuration entry %s=%s (overridden in command line)", Name, Value);
+ return true;
+ }
+
+ if (!strcasecmp(Name, "RemoveQuotesFromShortText")) EpgfixerSetup.quotedshorttext = atoi(Value);
+ else if (!strcasecmp(Name, "MoveDescriptionFromShortText")) EpgfixerSetup.blankbeforedescription = atoi(Value);
+ else if (!strcasecmp(Name, "RemoveRepeatedTitleFromShortText")) EpgfixerSetup.repeatedtitle = atoi(Value);
+ else if (!strcasecmp(Name, "RemoveDoubleQuotesFromShortText")) EpgfixerSetup.doublequotedshorttext = atoi(Value);
+ else if (!strcasecmp(Name, "RemoveUselessFormatting")) EpgfixerSetup.removeformatting = atoi(Value);
+ else if (!strcasecmp(Name, "MoveLongShortTextToDescription")) EpgfixerSetup.longshorttext = atoi(Value);
+ else if (!strcasecmp(Name, "PreventEqualShortTextAndDescription")) EpgfixerSetup.equalshorttextanddescription = atoi(Value);
+ else if (!strcasecmp(Name, "ReplaceBackticksWithSingleQuotes")) EpgfixerSetup.nobackticks = atoi(Value);
+ else if (!strcasecmp(Name, "FixStreamComponentDescriptions")) EpgfixerSetup.components = atoi(Value);
+ else if (!strcasecmp(Name, "StripHTMLEntities")) EpgfixerSetup.striphtml = atoi(Value);
+ else
+ return false;
+
+ return true;
}
bool cPluginEpgfixer::Service(const char *Id, void *Data)
diff --git a/epghandler.c b/epghandler.c
index b30ee1a..de898fc 100644
--- a/epghandler.c
+++ b/epghandler.c
@@ -5,272 +5,10 @@
*
*/
-#include <string.h>
-#include <vdr/tools.h>
-#include "epghandler.h"
#include "blacklist.h"
-#include "charset.h"
-#include "config.h"
#include "epgclone.h"
-#include "regexp.h"
-
-//
-// Original VDR bug fixes adapted from epg.c of VDR
-// by Klaus Schmidinger
-//
-
-static void StripControlCharacters(char *s)
-{
- if (s) {
- int len = strlen(s);
- while (len > 0) {
- int l = Utf8CharLen(s);
- uchar *p = (uchar *)s;
- if (l == 2 && *p == 0xC2) // UTF-8 sequence
- p++;
- if (*p == 0x86 || *p == 0x87) {
- memmove(s, p + 1, len - l + 1); // we also copy the terminating 0!
- len -= l;
- l = 0;
- }
- s += l;
- len -= l;
- }
- }
-}
-
-void cEpgfixerEpgHandler::FixOriginalEpgBugs(cEvent *event)
-{
- // Copy event title, shorttext and description to temporary variables
- // we don't want any "(null)" titles
- char *title = event->Title() ? strdup(event->Title()) : strdup("No title");
- char *shortText = event->ShortText() ? strdup(event->ShortText()) : NULL;
- char *description = event->Description() ? strdup(event->Description()) : NULL;
-
- // Some TV stations apparently have their own idea about how to fill in the
- // EPG data. Let's fix their bugs as good as we can:
-
- // Some channels put the ShortText in quotes and use either the ShortText
- // or the Description field, depending on how long the string is:
- //
- // Title
- // "ShortText". Description
- //
- if (EpgfixerSetup.quotedshorttext && (shortText == NULL) != (description == NULL)) {
- char *p = shortText ? shortText : description;
- if (*p == '"') {
- const char *delim = "\".";
- char *e = strstr(p + 1, delim);
- if (e) {
- *e = 0;
- char *s = strdup(p + 1);
- char *d = strdup(e + strlen(delim));
- free(shortText);
- free(description);
- shortText = s;
- description = d;
- }
- }
- }
-
- // Some channels put the Description into the ShortText (preceded
- // by a blank) if there is no actual ShortText and the Description
- // is short enough:
- //
- // Title
- // Description
- //
- if (EpgfixerSetup.blankbeforedescription && shortText && !description) {
- if (*shortText == ' ') {
- memmove(shortText, shortText + 1, strlen(shortText));
- description = shortText;
- shortText = NULL;
- }
- }
-
- // Sometimes they repeat the Title in the ShortText:
- //
- // Title
- // Title
- //
- if (EpgfixerSetup.repeatedtitle && shortText && strcmp(title, shortText) == 0) {
- free(shortText);
- shortText = NULL;
- }
-
- // Some channels put the ShortText between double quotes, which is nothing
- // but annoying (some even put a '.' after the closing '"'):
- //
- // Title
- // "ShortText"[.]
- //
- if (EpgfixerSetup.doublequotedshorttext && shortText && *shortText == '"') {
- int l = strlen(shortText);
- if (l > 2 && (shortText[l - 1] == '"' || (shortText[l - 1] == '.' && shortText[l - 2] == '"'))) {
- memmove(shortText, shortText + 1, l);
- char *p = strrchr(shortText, '"');
- if (p)
- *p = 0;
- }
- }
-
- // Some channels apparently try to do some formatting in the texts,
- // which is a bad idea because they have no way of knowing the width
- // of the window that will actually display the text.
- // Remove excess whitespace:
- if (EpgfixerSetup.removeformatting) {
- title = compactspace(title);
- shortText = compactspace(shortText);
- description = compactspace(description);
- }
-
-#define MAX_USEFUL_EPISODE_LENGTH 40
- // 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 (EpgfixerSetup.longshorttext && !isempty(shortText) && isempty(description)) {
- if (strlen(shortText) > MAX_USEFUL_EPISODE_LENGTH) {
- free(description);
- description = shortText;
- shortText = NULL;
- }
- }
-
- // Some channels put the same information into ShortText and Description.
- // In that case we delete one of them:
- if (EpgfixerSetup.equalshorttextanddescription && shortText && description && strcmp(shortText, description) == 0) {
- if (strlen(shortText) > MAX_USEFUL_EPISODE_LENGTH) {
- free(shortText);
- shortText = NULL;
- }
- else {
- free(description);
- description = NULL;
- }
- }
-
- // Some channels use the ` ("backtick") character, where a ' (single quote)
- // would be normally used. Actually, "backticks" in normal text don't make
- // much sense, so let's replace them:
- if (EpgfixerSetup.nobackticks) {
- strreplace(title, '`', '\'');
- strreplace(shortText, '`', '\'');
- strreplace(description, '`', '\'');
- }
-
- // The stream components have a "description" field which some channels
- // apparently have no idea of how to set correctly:
- const cComponents *components = event->Components();
- if (EpgfixerSetup.components && components) {
- for (int i = 0; i < components->NumComponents(); ++i) {
- tComponent *p = components->Component(i);
- switch (p->stream) {
- case 0x01: { // video
- if (p->description) {
- if (strcasecmp(p->description, "Video") == 0 ||
- strcasecmp(p->description, "Bildformat") == 0) {
- // Yes, we know it's video - that's what the 'stream' code
- // is for! But _which_ video is it?
- free(p->description);
- p->description = NULL;
- }
- }
- if (!p->description) {
- switch (p->type) {
- case 0x01:
- case 0x05: p->description = strdup("4:3"); break;
- case 0x02:
- case 0x03:
- case 0x06:
- case 0x07: p->description = strdup("16:9"); break;
- case 0x04:
- case 0x08: p->description = strdup(">16:9"); break;
- case 0x09:
- case 0x0D: p->description = strdup("HD 4:3"); break;
- case 0x0A:
- case 0x0B:
- case 0x0E:
- case 0x0F: p->description = strdup("HD 16:9"); break;
- case 0x0C:
- case 0x10: p->description = strdup("HD >16:9"); break;
- default: ;
- }
- }
- }
- break;
- case 0x02: { // audio
- if (p->description) {
- if (strcasecmp(p->description, "Audio") == 0) {
- // Yes, we know it's audio - that's what the 'stream' code
- // is for! But _which_ audio is it?
- free(p->description);
- p->description = NULL;
- }
- }
- if (!p->description) {
- switch (p->type) {
- case 0x05: p->description = strdup("Dolby Digital"); break;
- default: ; // all others will just display the language
- }
- }
- }
- break;
- default: ;
- }
- }
- }
-
- // VDR can't usefully handle newline characters in the title, shortText or component description of EPG
- // data, so let's always convert them to blanks (independent of the setting of EPGBugfixLevel):
- strreplace(title, '\n', ' ');
- strreplace(shortText, '\n', ' ');
- if (components) {
- for (int i = 0; i < components->NumComponents(); ++i) {
- tComponent *p = components->Component(i);
- if (p->description)
- strreplace(p->description, '\n', ' ');
- }
- }
- // Same for control characters:
- StripControlCharacters(title);
- StripControlCharacters(shortText);
- StripControlCharacters(description);
- // Set modified data back to event
- event->SetTitle(title);
- event->SetShortText(shortText);
- event->SetDescription(description);
-
- free(title);
- free(shortText);
- free(description);
-}
-
-bool cEpgfixerEpgHandler::FixBugs(cEvent *Event)
-{
- return EpgfixerRegexps.Apply(Event);
-}
-
-bool cEpgfixerEpgHandler::FixCharSets(cEvent *Event)
-{
- return EpgfixerCharSets.Apply(Event);
-}
-
-void cEpgfixerEpgHandler::StripHTML(cEvent *Event)
-{
- if (EpgfixerSetup.striphtml) {
- char *tmpstring = NULL;
- tmpstring = Event->Title() ? strdup(Event->Title()) : NULL;
- Event->SetTitle(striphtml(tmpstring));
- FREE(tmpstring);
- tmpstring = Event->ShortText() ? strdup(Event->ShortText()) : NULL;
- Event->SetShortText(striphtml(tmpstring));
- FREE(tmpstring);
- tmpstring = Event->Description() ? strdup(Event->Description()) : NULL;
- Event->SetDescription(striphtml(tmpstring));
- FREE(tmpstring);
- }
-}
+#include "tools.h"
+#include "epghandler.h"
bool cEpgfixerEpgHandler::FixEpgBugs(cEvent *Event)
{
diff --git a/epghandler.h b/epghandler.h
index cd5d51e..de090af 100644
--- a/epghandler.h
+++ b/epghandler.h
@@ -13,12 +13,6 @@
class cEpgfixerEpgHandler : public cEpgHandler
{
-private:
- void FixOriginalEpgBugs(cEvent *event);
- bool FixCharSets(cEvent *Event);
- bool FixBugs(cEvent *Event);
- void StripHTML(cEvent *Event);
-
public:
cEpgfixerEpgHandler(void) {};
virtual bool HandleEvent(cEvent *Event);
diff --git a/regexp.c b/regexp.c
index 9067911..50e11e1 100644
--- a/regexp.c
+++ b/regexp.c
@@ -78,6 +78,44 @@ void cRegexp::FreeCompiled()
}
}
+
+int cRegexp::ParseModifiers(char *modstring, int substitution)
+{
+ int i = 0;
+ int mods = 0;
+ // handle all modifiers
+ while (*(modstring + i) != 0) {
+ switch (*(modstring + i)) {
+ case 'g':
+ if (substitution)
+ replace = GLOBAL;
+ break;
+ case 'i':
+ mods |= PCRE_CASELESS;
+ break;
+ case 'm':
+ mods |= PCRE_MULTILINE;
+ break;
+ case 's':
+ mods |= PCRE_DOTALL;
+ break;
+ case 'u':
+ mods |= PCRE_UTF8;
+ break;
+ case 'x':
+ mods |= PCRE_EXTENDED;
+ break;
+ case 'X':
+ mods |= PCRE_EXTRA;
+ break;
+ default:
+ break;
+ }
+ i++;
+ }
+ return mods;
+}
+
void cRegexp::ParseRegexp(char *restring)
{
if (restring) {
@@ -87,37 +125,7 @@ void cRegexp::ParseRegexp(char *restring)
char *l = strrchr(restring, '/');
if (l) {
*l = 0;
- int i = 1;
- // handle all modifiers
- while (*(l + i) != 0) {
- switch (*(l + i)) {
- case 'g':
- if (restring[0] == 's')
- replace = GLOBAL;
- break;
- case 'i':
- modifiers = modifiers | PCRE_CASELESS;
- break;
- case 'm':
- modifiers = modifiers | PCRE_MULTILINE;
- break;
- case 's':
- modifiers = modifiers | PCRE_DOTALL;
- break;
- case 'u':
- modifiers = modifiers | PCRE_UTF8;
- break;
- case 'x':
- modifiers = modifiers | PCRE_EXTENDED;
- break;
- case 'X':
- modifiers = modifiers | PCRE_EXTRA;
- break;
- default:
- break;
- }
- i++;
- }
+ modifiers = ParseModifiers(l + 1, restring[0] == 's');
}
// parse regexp format 's///'
if (restring[0] == 's') {
@@ -200,13 +208,13 @@ bool cRegexp::Apply(cEvent *Event)
}
if (!*tmpstring)
tmpstring = "";
+ int tmpstringlen = strlen(*tmpstring);
int ovector[OVECCOUNT];
int rc = 0;
if (replace != NONE) {// find and replace
int last_match_end = -1;
int options = 0;
int start_offset = 0;
- int tmpstringlen = strlen(*tmpstring);
cString resultstring = "";
// loop through matches
while ((rc = pcre_exec(re, sd, *tmpstring, tmpstringlen, start_offset, options, ovector, OVECCOUNT)) > 0) {
@@ -243,7 +251,7 @@ bool cRegexp::Apply(cEvent *Event)
}
else {// use backreferences
const char *capturestring;
- rc = pcre_exec(re, sd, *tmpstring, strlen(*tmpstring), 0, 0, ovector, OVECCOUNT);
+ rc = pcre_exec(re, sd, *tmpstring, tmpstringlen, 0, 0, ovector, OVECCOUNT);
if (rc == 0) {
error("maximum number of captured substrings is %d\n", OVECCOUNT / 3 - 1);
}
diff --git a/regexp.h b/regexp.h
index c1565e2..25efae9 100644
--- a/regexp.h
+++ b/regexp.h
@@ -30,6 +30,7 @@ private:
pcre_extra *sd;
void Compile();
void FreeCompiled();
+ int ParseModifiers(char *modstring, int substitution = 0);
void ParseRegexp(char *restring);
public:
diff --git a/setup_menu.c b/setup_menu.c
index 19f84a2..06dbaae 100644
--- a/setup_menu.c
+++ b/setup_menu.c
@@ -167,7 +167,7 @@ public:
cMenuSetupEpgfixer::cMenuSetupEpgfixer(void)
{
- memcpy(&newconfig, &EpgfixerSetup, sizeof(cEpgfixerSetup));
+ newconfig = EpgfixerSetup;
Set();
}
@@ -223,7 +223,7 @@ void cMenuSetupEpgfixer::Set(void)
void cMenuSetupEpgfixer::Store(void)
{
- memcpy(&EpgfixerSetup, &newconfig, sizeof(cEpgfixerSetup));
+ EpgfixerSetup = newconfig;
SetupStore("RemoveQuotesFromShortText", EpgfixerSetup.quotedshorttext);
SetupStore("MoveDescriptionFromShortText", EpgfixerSetup.blankbeforedescription);
diff --git a/tools.c b/tools.c
index 8f86ed0..0494166 100644
--- a/tools.c
+++ b/tools.c
@@ -8,10 +8,270 @@
#include <stdlib.h>
#include <string.h>
#include <vdr/thread.h>
-
+#include "charset.h"
+#include "config.h"
+#include "regexp.h"
#include "tools.h"
//
+// Original VDR bug fixes adapted from epg.c of VDR
+// by Klaus Schmidinger
+//
+
+static void StripControlCharacters(char *s)
+{
+ if (s) {
+ int len = strlen(s);
+ while (len > 0) {
+ int l = Utf8CharLen(s);
+ uchar *p = (uchar *)s;
+ if (l == 2 && *p == 0xC2) // UTF-8 sequence
+ p++;
+ if (*p == 0x86 || *p == 0x87) {
+ memmove(s, p + 1, len - l + 1); // we also copy the terminating 0!
+ len -= l;
+ l = 0;
+ }
+ s += l;
+ len -= l;
+ }
+ }
+}
+
+void FixOriginalEpgBugs(cEvent *event)
+{
+ // Copy event title, shorttext and description to temporary variables
+ // we don't want any "(null)" titles
+ char *title = event->Title() ? strdup(event->Title()) : strdup("No title");
+ char *shortText = event->ShortText() ? strdup(event->ShortText()) : NULL;
+ char *description = event->Description() ? strdup(event->Description()) : NULL;
+
+ // Some TV stations apparently have their own idea about how to fill in the
+ // EPG data. Let's fix their bugs as good as we can:
+
+ // Some channels put the ShortText in quotes and use either the ShortText
+ // or the Description field, depending on how long the string is:
+ //
+ // Title
+ // "ShortText". Description
+ //
+ if (EpgfixerSetup.quotedshorttext && (shortText == NULL) != (description == NULL)) {
+ char *p = shortText ? shortText : description;
+ if (*p == '"') {
+ const char *delim = "\".";
+ char *e = strstr(p + 1, delim);
+ if (e) {
+ *e = 0;
+ char *s = strdup(p + 1);
+ char *d = strdup(e + strlen(delim));
+ free(shortText);
+ free(description);
+ shortText = s;
+ description = d;
+ }
+ }
+ }
+
+ // Some channels put the Description into the ShortText (preceded
+ // by a blank) if there is no actual ShortText and the Description
+ // is short enough:
+ //
+ // Title
+ // Description
+ //
+ if (EpgfixerSetup.blankbeforedescription && shortText && !description) {
+ if (*shortText == ' ') {
+ memmove(shortText, shortText + 1, strlen(shortText));
+ description = shortText;
+ shortText = NULL;
+ }
+ }
+
+ // Sometimes they repeat the Title in the ShortText:
+ //
+ // Title
+ // Title
+ //
+ if (EpgfixerSetup.repeatedtitle && shortText && strcmp(title, shortText) == 0) {
+ free(shortText);
+ shortText = NULL;
+ }
+
+ // Some channels put the ShortText between double quotes, which is nothing
+ // but annoying (some even put a '.' after the closing '"'):
+ //
+ // Title
+ // "ShortText"[.]
+ //
+ if (EpgfixerSetup.doublequotedshorttext && shortText && *shortText == '"') {
+ int l = strlen(shortText);
+ if (l > 2 && (shortText[l - 1] == '"' || (shortText[l - 1] == '.' && shortText[l - 2] == '"'))) {
+ memmove(shortText, shortText + 1, l);
+ char *p = strrchr(shortText, '"');
+ if (p)
+ *p = 0;
+ }
+ }
+
+ // Some channels apparently try to do some formatting in the texts,
+ // which is a bad idea because they have no way of knowing the width
+ // of the window that will actually display the text.
+ // Remove excess whitespace:
+ if (EpgfixerSetup.removeformatting) {
+ title = compactspace(title);
+ shortText = compactspace(shortText);
+ description = compactspace(description);
+ }
+
+#define MAX_USEFUL_EPISODE_LENGTH 40
+ // 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 (EpgfixerSetup.longshorttext && !isempty(shortText) && isempty(description)) {
+ if (strlen(shortText) > MAX_USEFUL_EPISODE_LENGTH) {
+ free(description);
+ description = shortText;
+ shortText = NULL;
+ }
+ }
+
+ // Some channels put the same information into ShortText and Description.
+ // In that case we delete one of them:
+ if (EpgfixerSetup.equalshorttextanddescription && shortText && description && strcmp(shortText, description) == 0) {
+ if (strlen(shortText) > MAX_USEFUL_EPISODE_LENGTH) {
+ free(shortText);
+ shortText = NULL;
+ }
+ else {
+ free(description);
+ description = NULL;
+ }
+ }
+
+ // Some channels use the ` ("backtick") character, where a ' (single quote)
+ // would be normally used. Actually, "backticks" in normal text don't make
+ // much sense, so let's replace them:
+ if (EpgfixerSetup.nobackticks) {
+ strreplace(title, '`', '\'');
+ strreplace(shortText, '`', '\'');
+ strreplace(description, '`', '\'');
+ }
+
+ // The stream components have a "description" field which some channels
+ // apparently have no idea of how to set correctly:
+ const cComponents *components = event->Components();
+ if (EpgfixerSetup.components && components) {
+ for (int i = 0; i < components->NumComponents(); ++i) {
+ tComponent *p = components->Component(i);
+ switch (p->stream) {
+ case 0x01: { // video
+ if (p->description) {
+ if (strcasecmp(p->description, "Video") == 0 ||
+ strcasecmp(p->description, "Bildformat") == 0) {
+ // Yes, we know it's video - that's what the 'stream' code
+ // is for! But _which_ video is it?
+ free(p->description);
+ p->description = NULL;
+ }
+ }
+ if (!p->description) {
+ switch (p->type) {
+ case 0x01:
+ case 0x05: p->description = strdup("4:3"); break;
+ case 0x02:
+ case 0x03:
+ case 0x06:
+ case 0x07: p->description = strdup("16:9"); break;
+ case 0x04:
+ case 0x08: p->description = strdup(">16:9"); break;
+ case 0x09:
+ case 0x0D: p->description = strdup("HD 4:3"); break;
+ case 0x0A:
+ case 0x0B:
+ case 0x0E:
+ case 0x0F: p->description = strdup("HD 16:9"); break;
+ case 0x0C:
+ case 0x10: p->description = strdup("HD >16:9"); break;
+ default: ;
+ }
+ }
+ }
+ break;
+ case 0x02: { // audio
+ if (p->description) {
+ if (strcasecmp(p->description, "Audio") == 0) {
+ // Yes, we know it's audio - that's what the 'stream' code
+ // is for! But _which_ audio is it?
+ free(p->description);
+ p->description = NULL;
+ }
+ }
+ if (!p->description) {
+ switch (p->type) {
+ case 0x05: p->description = strdup("Dolby Digital"); break;
+ default: ; // all others will just display the language
+ }
+ }
+ }
+ break;
+ default: ;
+ }
+ }
+ }
+
+ // VDR can't usefully handle newline characters in the title, shortText or component description of EPG
+ // data, so let's always convert them to blanks (independent of the setting of EPGBugfixLevel):
+ strreplace(title, '\n', ' ');
+ strreplace(shortText, '\n', ' ');
+ if (components) {
+ for (int i = 0; i < components->NumComponents(); ++i) {
+ tComponent *p = components->Component(i);
+ if (p->description)
+ strreplace(p->description, '\n', ' ');
+ }
+ }
+ // Same for control characters:
+ StripControlCharacters(title);
+ StripControlCharacters(shortText);
+ StripControlCharacters(description);
+ // Set modified data back to event
+ event->SetTitle(title);
+ event->SetShortText(shortText);
+ event->SetDescription(description);
+
+ free(title);
+ free(shortText);
+ free(description);
+}
+
+bool FixBugs(cEvent *Event)
+{
+ return EpgfixerRegexps.Apply(Event);
+}
+
+bool FixCharSets(cEvent *Event)
+{
+ return EpgfixerCharSets.Apply(Event);
+}
+
+void StripHTML(cEvent *Event)
+{
+ if (EpgfixerSetup.striphtml) {
+ char *tmpstring = NULL;
+ tmpstring = Event->Title() ? strdup(Event->Title()) : NULL;
+ Event->SetTitle(striphtml(tmpstring));
+ FREE(tmpstring);
+ tmpstring = Event->ShortText() ? strdup(Event->ShortText()) : NULL;
+ Event->SetShortText(striphtml(tmpstring));
+ FREE(tmpstring);
+ tmpstring = Event->Description() ? strdup(Event->Description()) : NULL;
+ Event->SetDescription(striphtml(tmpstring));
+ FREE(tmpstring);
+ }
+}
+
+//
// HTML conversion code taken from RSS Reader plugin for VDR
// http://www.saunalahti.fi/~rahrenbe/vdr/rssreader/
// by Rolf Ahrenberg
@@ -210,10 +470,12 @@ void cAddEventThread::Action(void)
Lock();
while (schedules && (e = list->First()) != NULL) {
cSchedule *schedule = (cSchedule *)schedules->GetSchedule(Channels.GetByChannelID(e->GetChannelID()), true);
- schedule->AddEvent(e->GetEvent());
- EpgHandlers.SortSchedule(schedule);
- EpgHandlers.DropOutdated(schedule, e->GetEvent()->StartTime(), e->GetEvent()->EndTime(), e->GetEvent()->TableID(), e->GetEvent()->Version());
- list->Del(e);
+ if (schedule) {
+ schedule->AddEvent(e->GetEvent());
+ EpgHandlers.SortSchedule(schedule);
+ EpgHandlers.DropOutdated(schedule, e->GetEvent()->StartTime(), e->GetEvent()->EndTime(), e->GetEvent()->TableID(), e->GetEvent()->Version());
+ list->Del(e);
+ }
}
Unlock();
cCondWait::SleepMs(10);
diff --git a/tools.h b/tools.h
index d77574f..21dbd64 100644
--- a/tools.h
+++ b/tools.h
@@ -13,10 +13,23 @@
#include <vdr/epg.h>
#include <vdr/tools.h>
-#define error(x...) esyslog("EPGFixer: " x);
+#ifdef DEBUG
+#define debug(x...) dsyslog("EPGFixer: " x);
+#else
+#define debug(x...) ;
+#endif
+#define error(x...) esyslog("ERROR: " x);
+
#define FREE(x) { free(x); x = NULL; }
+// --- EPG bug fixes ----------------------------------------------------
+
+void FixOriginalEpgBugs(cEvent *event);
+bool FixCharSets(cEvent *Event);
+bool FixBugs(cEvent *Event);
+void StripHTML(cEvent *Event);
+
// --- Add event to schedule --------------------------------------------
void AddEvent(cEvent *event, tChannelID ChannelID);