summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--HISTORY9
-rw-r--r--Makefile2
-rw-r--r--README31
-rw-r--r--blacklist.c36
-rw-r--r--blacklist.h27
-rw-r--r--charset.c48
-rw-r--r--charset.h9
-rw-r--r--epgclone.c91
-rw-r--r--epgclone.h31
-rw-r--r--epgfixer.c41
-rw-r--r--epgfixer/blacklist.conf3
-rw-r--r--epgfixer/charset.conf10
-rw-r--r--epgfixer/epgclone.conf2
-rw-r--r--epghandler.c14
-rw-r--r--epghandler.h2
-rw-r--r--po/fi_FI.po24
-rw-r--r--regexp.c13
-rw-r--r--regexp.h6
-rw-r--r--setup_menu.c48
-rw-r--r--tools.c88
-rw-r--r--tools.h44
21 files changed, 481 insertions, 98 deletions
diff --git a/HISTORY b/HISTORY
index 8c1a1c0..6d0bce3 100644
--- a/HISTORY
+++ b/HISTORY
@@ -1,5 +1,14 @@
VDR Plugin 'epgfixer' Revision History
--------------------------------------
+
+2012-??-??: Version 0.2.0
+
+- Support for ignoring EPG data for selected channels.
+- Support for copying EPG data from one channel to another.
+- Fix character set conversion for selected channels.
+- Fix and improve Makefile (thanks to Ville Skyttä and Rolf Ahrenberg).
+- Fix compiling with g++-4.7.
+
2012-05-05: Version 0.1.0
- Support for character set conversion for selected channels.
diff --git a/Makefile b/Makefile
index 90871de..3a64ae7 100644
--- a/Makefile
+++ b/Makefile
@@ -62,7 +62,7 @@ endif
### The object files (add further files here):
-OBJS = $(PLUGIN).o charset.o config.o epghandler.o regexp.o setup_menu.o tools.o
+OBJS = $(PLUGIN).o blacklist.o charset.o config.o epgclone.o epghandler.o regexp.o setup_menu.o tools.o
ifeq ($(REGEXLIB), pcre)
LIBS += $(shell pcre-config --libs-posix)
diff --git a/README b/README
index 68ddf32..4211d60 100644
--- a/README
+++ b/README
@@ -23,9 +23,11 @@ Features:
- Modifying EPG data using regular expressions. Correctly named back references
are placed to the named EPG field.
- Character set conversions for channel using incorrect encoding.
-- Both regular expressions and character set conversions can be applied to
+- Blacklists for ignoring EPG data from stream.
+- Regular expressions, character set conversions and blacklists can be applied to
either all channels or only to selected channels.
-- Editing regular expressions and character set conversions through setup menu.
+- Cloning EPG data from one channel to another.
+- Editing all settings through setup menu.
- EPG bug fixes included in VDR individually selectable from
setup menu.
@@ -42,10 +44,11 @@ make plugins
Configuration:
-Regular expressions and character set conversions are defined in regexp.conf
-and charset.conf, respectively, located in VDR's configuration directory for
-plugins. Check the example configuration files under "epgfixer" subdirectory
-for further information.
+Regular expressions, character set conversions, blacklists and EPG clonings
+are defined in regexp.conf, charset.conf, blacklist.conf and epgclone.conf,
+respectively, located in "epgfixer" subdirectory of VDR's configuration
+directory for plugins. Check the example configuration files under "epgfixer"
+subdirectory for further information.
General syntax of configuration files:
- Lines beginning with # are regarded as comments.
@@ -65,5 +68,17 @@ Syntax of regexp.conf line is "Channel_list:Parsed_epg_field=Regexp" with:
content of the target EPG field, respectively.
- Several regular expressions may be applied to same field.
-Syntax of charset.conf line is "Channel_list:OriginalCharSet" with:
-- OriginalCharSet is a name of a character set (e.g. iso8859-1).
+Syntax of charset.conf line is "Channel_list:BroadcastCharset=OriginalCharSet"
+with:
+- OriginalCharSet and BroadcastCharset are names of a character set
+ (e.g. iso8859-1).
+- OriginalCharSet is the real character set of EPG data.
+- BroadcastCharset is the optional incorrect character set received in data
+ stream.
+- If no BroadcastCharset is defined ISO6937 is assumed.
+
+Syntax of blacklist.conf line is "Channel_list" with:
+- Only comma separated list of channel to be ignored.
+
+Syntax of epgclone.conf line is "FromChannel=ToChannel" with:
+- Copy EPG data of FromChannel into ToChannel.
diff --git a/blacklist.c b/blacklist.c
new file mode 100644
index 0000000..4bacf2c
--- /dev/null
+++ b/blacklist.c
@@ -0,0 +1,36 @@
+/*
+ * blacklist.c: Blacklist list item
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ */
+
+#include "blacklist.h"
+
+/* Global instance */
+cEpgfixerList<cBlacklist, cChannel> EpgfixerBlacklists;
+
+
+bool cBlacklist::Apply(cChannel *Channel)
+{
+ if (enabled && IsActive(Channel->GetChannelID()))
+ return true;
+ return false;
+}
+
+void cBlacklist::SetFromString(char *s, bool Enabled)
+{
+ Free();
+ enabled = Enabled;
+ if (s[0] == '!')
+ string = strdup(s+1);
+ else
+ string = strdup(s);
+ if (s[0] == '!' || s[0] == '#')
+ enabled = false;
+ char *p = (s[0] == '#') ? NULL : s;
+ if (p) {
+ char *p = (s[0] == '!') ? s+1 : s;
+ numchannels = LoadChannelsFromString(p);
+ }
+}
diff --git a/blacklist.h b/blacklist.h
new file mode 100644
index 0000000..1d60185
--- /dev/null
+++ b/blacklist.h
@@ -0,0 +1,27 @@
+/*
+ * blacklist.h: Blacklist list item
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ */
+
+#ifndef __EPGFIXER_BLACKLIST_H_
+#define __EPGFIXER_BLACKLIST_H_
+
+#include "tools.h"
+#include <vdr/epg.h>
+
+class cBlacklist : public cListItem
+{
+public:
+ cBlacklist() {}
+ virtual ~cBlacklist() {}
+ using cListItem::Apply;
+ virtual bool Apply(cChannel *Channel);
+ void SetFromString(char *string, bool Enabled);
+};
+
+// Global instance
+extern cEpgfixerList<cBlacklist, cChannel> EpgfixerBlacklists;
+
+#endif //__EPGFIXER_BLACKLIST_H_
diff --git a/charset.c b/charset.c
index 84056bf..c502e90 100644
--- a/charset.c
+++ b/charset.c
@@ -6,39 +6,45 @@
*/
#include "charset.h"
-#include <unistd.h>
/* Global instance */
-cEpgfixerList<cCharSet> EpgfixerCharSets;
+cEpgfixerList<cCharSet, cEvent> EpgfixerCharSets;
cCharSet::cCharSet()
{
- charset = NULL;
+ origcharset = NULL;
+ realcharset = NULL;
}
cCharSet::~cCharSet(void)
{
- free(charset);
+ free(origcharset);
+ free(realcharset);
}
bool cCharSet::Apply(cEvent *Event)
{
if (enabled && IsActive(Event->ChannelID())) {
- cCharSetConv conv(charset, cCharSetConv::SystemCharacterTable());
- Event->SetTitle(conv.Convert(Event->Title()));
- Event->SetShortText(conv.Convert(Event->ShortText()));
- Event->SetDescription(conv.Convert(Event->Description()));
+ cCharSetConv backconv(cCharSetConv::SystemCharacterTable(), origcharset ? origcharset : "iso6937");
+ cString title(backconv.Convert(Event->Title()));
+ cString shortText(backconv.Convert(Event->ShortText()));
+ cString description(backconv.Convert(Event->Description()));
+ cCharSetConv conv(realcharset, cCharSetConv::SystemCharacterTable());
+ Event->SetTitle(conv.Convert(title));
+ Event->SetShortText(conv.Convert(shortText));
+ Event->SetDescription(conv.Convert(description));
}
return false;
}
void cCharSet::SetFromString(char *s, bool Enabled)
{
- FREE(charset);
+ FREE(origcharset);
+ FREE(realcharset);
Free();
enabled = Enabled;
if (s[0] == '!')
- string = strdup(s+1);
+ string = strdup(s + 1);
else
string = strdup(s);
if (s[0] == '!' || s[0] == '#')
@@ -46,19 +52,19 @@ void cCharSet::SetFromString(char *s, bool Enabled)
char *p = (s[0] == '#') ? NULL : s;
if (p) {
char *p = (s[0] == '!') ? s+1 : s;
- char *f = strchr(p, ':');
- if (f) {
- *f = 0;
- charset = strdup(f + 1);
+ char *r = strchr(p, ':');
+ if (r) {
+ *r = 0;
numchannels = LoadChannelsFromString(p);
+ p = r + 1;
+ }
+ r = strchr(p, '=');
+ if (r) {
+ *r = 0;
+ origcharset = strdup(p);
+ realcharset = strdup(r + 1);
}
else
- charset = strdup(p);
+ realcharset = strdup(p);
}
}
-
-void cCharSet::PrintConfigLineToFile(FILE *f)
-{
- if (f)
- fprintf(f, "%s%s\n", enabled ? "" : "!", string);
-}
diff --git a/charset.h b/charset.h
index f73a964..cfcee79 100644
--- a/charset.h
+++ b/charset.h
@@ -10,22 +10,21 @@
#include "tools.h"
#include <vdr/epg.h>
-#include <vdr/tools.h>
-#include <stdio.h>
class cCharSet : public cListItem
{
private:
- char *charset;
+ char *origcharset;
+ char *realcharset;
public:
cCharSet();
virtual ~cCharSet();
+ using cListItem::Apply;
virtual bool Apply(cEvent *Event);
void SetFromString(char *string, bool Enabled);
- virtual void PrintConfigLineToFile(FILE *f);
};
// Global instance
-extern cEpgfixerList<cCharSet> EpgfixerCharSets;
+extern cEpgfixerList<cCharSet, cEvent> EpgfixerCharSets;
#endif //__EPGFIXER_CHARSET_H_
diff --git a/epgclone.c b/epgclone.c
new file mode 100644
index 0000000..9fcff8e
--- /dev/null
+++ b/epgclone.c
@@ -0,0 +1,91 @@
+/*
+ * epgclone.c: EpgClone list item
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ */
+
+#include "epgclone.h"
+
+/* Global instance */
+cEpgfixerList<cEpgClone, cEvent> EpgfixerEpgClones;
+
+cEpgClone::cEpgClone()
+{
+ dest_num = 0;
+ dest_str = NULL;
+}
+
+cEpgClone::~cEpgClone()
+{
+ free(dest_str);
+}
+
+void cEpgClone::CloneEvent(cEvent *Source, cEvent *Dest) {
+ Dest->SetEventID(Source->EventID());
+ Dest->SetTableID(Source->TableID());
+ Dest->SetVersion(Source->Version());
+ Dest->SetRunningStatus(Source->RunningStatus());
+ Dest->SetTitle(Source->Title());
+ Dest->SetShortText(Source->ShortText());
+ Dest->SetDescription(Source->Description());
+ cComponents *components = new cComponents();
+ if (Source->Components()) {
+ for (int i = 0; i < Source->Components()->NumComponents(); ++i)
+ components->SetComponent(i, Source->Components()->Component(i)->ToString());
+ }
+ Dest->SetComponents(components);
+ uchar contents[MaxEventContents];
+ for (int i = 0; i < MaxEventContents; ++i)
+ contents[i] = Source->Contents(i);
+ Dest->SetContents(contents);
+ Dest->SetParentalRating(Source->ParentalRating());
+ Dest->SetStartTime(Source->StartTime());
+ Dest->SetDuration(Source->Duration());
+ Dest->SetVps(Source->Vps());
+ if (Source->Seen())
+ Dest->SetSeen();
+ tChannelID channelID;
+ if (dest_num)
+ channelID = Channels.GetByNumber(dest_num)->GetChannelID();
+ else
+ channelID.FromString(dest_str);
+ AddEvent(Dest, channelID);
+}
+
+bool cEpgClone::Apply(cEvent *Event)
+{
+ if (Event && enabled && IsActive(Event->ChannelID())) {
+ cEvent *event = new cEvent(Event->EventID());
+ CloneEvent(Event, event);
+ return true;
+ }
+ return false;
+}
+
+void cEpgClone::SetFromString(char *s, bool Enabled)
+{
+ dest_num = 0;
+ FREE(dest_str);
+ Free();
+ enabled = Enabled;
+ if (s[0] == '!')
+ string = strdup(s+1);
+ else
+ string = strdup(s);
+ if (s[0] == '!' || s[0] == '#')
+ enabled = false;
+ char *p = (s[0] == '#') ? NULL : s;
+ if (p) {
+ char *p = (s[0] == '!') ? s+1 : s;
+ char *f = strchr(p, '=');
+ if (f) {
+ *f = 0;
+ if (atoi(f + 1))
+ dest_num = atoi(f + 1);
+ else
+ dest_str = strdup(f + 1);
+ numchannels = LoadChannelsFromString(p);
+ }
+ }
+}
diff --git a/epgclone.h b/epgclone.h
new file mode 100644
index 0000000..e0a4aa7
--- /dev/null
+++ b/epgclone.h
@@ -0,0 +1,31 @@
+/*
+ * epgclone.h: EpgClone list item
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ */
+
+#ifndef __EPGFIXER_EPGCLONE_H_
+#define __EPGFIXER_EPGCLONE_H_
+
+#include "tools.h"
+#include <vdr/epg.h>
+
+class cEpgClone : public cListItem
+{
+private:
+ int dest_num;
+ char *dest_str;
+ void CloneEvent(cEvent *Source, cEvent *Dest);
+public:
+ cEpgClone();
+ virtual ~cEpgClone();
+ using cListItem::Apply;
+ virtual bool Apply(cEvent *Event);
+ void SetFromString(char *string, bool Enabled);
+};
+
+// Global instance
+extern cEpgfixerList<cEpgClone, cEvent> EpgfixerEpgClones;
+
+#endif //__EPGFIXER_EPGCLONE_H_
diff --git a/epgfixer.c b/epgfixer.c
index 7308b0c..bbf635b 100644
--- a/epgfixer.c
+++ b/epgfixer.c
@@ -7,7 +7,9 @@
#include <vdr/plugin.h>
#include <vdr/i18n.h>
+#include "blacklist.h"
#include "charset.h"
+#include "epgclone.h"
#include "regexp.h"
#include "setup_menu.h"
#include "epghandler.h"
@@ -20,7 +22,7 @@
#define GITVERSION ""
#endif
-static const char VERSION[] = "0.1.0" GITVERSION;
+static const char VERSION[] = "0.2.0" GITVERSION;
static const char DESCRIPTION[] = trNOOP("Fix bugs in EPG");
class cPluginEpgfixer : public cPlugin {
@@ -80,6 +82,10 @@ bool cPluginEpgfixer::Initialize(void)
EpgfixerRegexps.ReloadConfigFile();
EpgfixerCharSets.SetConfigFile(AddDirectory(cPlugin::ConfigDirectory(PLUGIN_NAME_I18N), "charset.conf")); // allowed only via main thread!);
EpgfixerCharSets.ReloadConfigFile();
+ EpgfixerBlacklists.SetConfigFile(AddDirectory(cPlugin::ConfigDirectory(PLUGIN_NAME_I18N), "blacklist.conf")); // allowed only via main thread!);
+ EpgfixerBlacklists.ReloadConfigFile();
+ EpgfixerEpgClones.SetConfigFile(AddDirectory(cPlugin::ConfigDirectory(PLUGIN_NAME_I18N), "epgclone.conf")); // allowed only via main thread!);
+ EpgfixerEpgClones.ReloadConfigFile();
return new cEpgfixerEpgHandler();
}
@@ -149,10 +155,16 @@ bool cPluginEpgfixer::Service(const char *Id, void *Data)
const char **cPluginEpgfixer::SVDRPHelpPages(void)
{
static const char *HelpPages[] = {
+ "RLAL\n"
+ " Reload all configs.",
"RLRE\n"
" Reload regexp.conf.",
"RLCH\n"
" Reload charset.conf.",
+ "RLBL\n"
+ " Reload blacklist.conf.",
+ "RLEP\n"
+ " Reload epgclone.conf.",
NULL
};
return HelpPages;
@@ -176,6 +188,33 @@ cString cPluginEpgfixer::SVDRPCommand(const char *Command, const char *Option, i
return cString("Reloading charset.conf failed");
}
}
+ else if (strcasecmp(Command, "RLBL") == 0) {
+ if (EpgfixerBlacklists.ReloadConfigFile()) {
+ return cString("Reloaded blacklist.conf");
+ } else {
+ ReplyCode = 554; // Requested action failed
+ return cString("Reloading blacklist.conf failed");
+ }
+ }
+ else if (strcasecmp(Command, "RLEP") == 0) {
+ if (EpgfixerEpgClones.ReloadConfigFile()) {
+ return cString("Reloaded epgclone.conf");
+ } else {
+ ReplyCode = 554; // Requested action failed
+ return cString("Reloading epgclone.conf failed");
+ }
+ }
+ else if (strcasecmp(Command, "REL") == 0) {
+ if (EpgfixerCharSets.ReloadConfigFile() &&
+ EpgfixerCharSets.ReloadConfigFile() &&
+ EpgfixerBlacklists.ReloadConfigFile() &&
+ EpgfixerEpgClones.ReloadConfigFile()) {
+ return cString("Reloaded all configs");
+ } else {
+ ReplyCode = 554; // Requested action failed
+ return cString("Reloading all or some configs failed");
+ }
+ }
return NULL;
}
diff --git a/epgfixer/blacklist.conf b/epgfixer/blacklist.conf
new file mode 100644
index 0000000..7cd9ced
--- /dev/null
+++ b/epgfixer/blacklist.conf
@@ -0,0 +1,3 @@
+# Ignore EPG data for channels 1, 2 and 3
+#1,2,3
+
diff --git a/epgfixer/charset.conf b/epgfixer/charset.conf
index 18788c8..d2b14b3 100644
--- a/epgfixer/charset.conf
+++ b/epgfixer/charset.conf
@@ -1,6 +1,8 @@
# Convert character set of channels 1, 2 and 3 from iso8859-1 to character set
-# used by VDR
-#1,2,3:iso8859-1
+# used by VDR. Used for channels which broadcast incorrect character set
+# (in this example iso8859-9).
+#1,2,3:iso8859-9=iso8859-1
# Convert character set of all channels from iso8859-1 to character set
-# used by VDR
-#iso8859-1
+# used by VDR. Used for channels which do not broadcast any character set but
+# use a non-standard character set.
+#1,2,3:iso8859-1
diff --git a/epgfixer/epgclone.conf b/epgfixer/epgclone.conf
new file mode 100644
index 0000000..11ba183
--- /dev/null
+++ b/epgfixer/epgclone.conf
@@ -0,0 +1,2 @@
+# Copy EPG data from channel 1 to 3
+#1=3
diff --git a/epghandler.c b/epghandler.c
index 68e7a28..2dadd33 100644
--- a/epghandler.c
+++ b/epghandler.c
@@ -6,8 +6,10 @@
*/
#include "epghandler.h"
-#include "config.h"
+#include "blacklist.h"
#include "charset.h"
+#include "config.h"
+#include "epgclone.h"
#include "regexp.h"
#include <vdr/tools.h>
#include <string.h>
@@ -267,3 +269,13 @@ bool cEpgfixerEpgHandler::FixEpgBugs(cEvent *Event)
FixBugs(Event);
return false;
}
+
+bool cEpgfixerEpgHandler::HandleEvent(cEvent *Event)
+{
+ return EpgfixerEpgClones.Apply(Event);
+}
+
+bool cEpgfixerEpgHandler::IgnoreChannel(const cChannel *Channel)
+{
+ return EpgfixerBlacklists.Apply((cChannel *)Channel);
+}
diff --git a/epghandler.h b/epghandler.h
index cc38378..657fffc 100644
--- a/epghandler.h
+++ b/epghandler.h
@@ -19,6 +19,8 @@ private:
void StripHTML(cEvent *Event);
public:
cEpgfixerEpgHandler(void) {};
+ virtual bool HandleEvent(cEvent *Event);
+ virtual bool IgnoreChannel(const cChannel *Channel);
virtual bool FixEpgBugs(cEvent *Event);
};
diff --git a/po/fi_FI.po b/po/fi_FI.po
index de11e7c..d4b8b00 100644
--- a/po/fi_FI.po
+++ b/po/fi_FI.po
@@ -5,10 +5,10 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: vdr-epgfixer 0.1.0\n"
+"Project-Id-Version: vdr-epgfixer 0.2.0\n"
"Report-Msgid-Bugs-To: <see README>\n"
-"POT-Creation-Date: 2012-05-05 19:01+0300\n"
-"PO-Revision-Date: 2012-05-05 18:25+0300\n"
+"POT-Creation-Date: 2012-05-09 23:25+0300\n"
+"PO-Revision-Date: 2012-05-09 23:20+0300\n"
"Last-Translator: Matti Lehtimäki <matti.lehtimaki@gmail.com>\n"
"Language-Team: Finnish <vdr@linuxtv.org>\n"
"MIME-Version: 1.0\n"
@@ -19,7 +19,7 @@ msgstr ""
msgid "Fix bugs in EPG"
msgstr "Korjaa virheitä EPG:ssä"
-msgid " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789%~\\/?!()[]{}<>$^*.,:;-=#"
+msgid "RegexpChars$ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789%~\\/?!()[]{}<>$^*.,:;-=#"
msgstr " abcdefghijklmnopqrstuvwxyzåäöABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ0123456789%~\\/?!()[]{}<>$^*.,:;-=#"
msgid "Button$Cancel"
@@ -37,8 +37,20 @@ msgstr "Merkistömuunnokset"
msgid "Edit character set conversions."
msgstr "Muokkaa merkistömuunnoksia."
+msgid "EPG blacklists"
+msgstr "Ohjelmaoppaan mustat listat"
+
+msgid "Edit EPG blacklists."
+msgstr "Muokkaa ohjelmaoppaan mustia listoja. Mustilla listoilla voi estää ohjelmatietojen käsittelyn valituilta kanavilta."
+
+msgid "EPG cloning"
+msgstr "Ohjelmatietojen kopiointi"
+
+msgid "Edit EPG data cloning."
+msgstr "Muokkaa ohjelmatietojen kopiointia. Tällä voit kopioida kanavan ohjelmatiedot toiselle kanavalle."
+
msgid "--- EPG bugfixes ---"
-msgstr "--- EPG korjaukset ---"
+msgstr "--- Ohjelmaoppaan korjaukset ---"
msgid "Remove quotes from ShortText"
msgstr "Poista lainaukset lyhyestä kuvauksesta"
@@ -54,7 +66,7 @@ msgstr ""
"Otsikko\n"
"\"Lyhyt kuvaus\". Kuvaus"
-msgid "Move Description from ShortText."
+msgid "Move Description from ShortText"
msgstr "Siirrä kuvaus lyhyeen kuvaukseen"
msgid ""
diff --git a/regexp.c b/regexp.c
index dd6856c..bef3590 100644
--- a/regexp.c
+++ b/regexp.c
@@ -6,10 +6,9 @@
*/
#include "regexp.h"
-#include <unistd.h>
/* Global instance */
-cEpgfixerList<cRegexp> EpgfixerRegexps;
+cEpgfixerList<cRegexp, cEvent> EpgfixerRegexps;
const char *strSources[] = { "title","shorttext","description","undefined" };
@@ -178,16 +177,6 @@ bool cRegexp::Apply(cEvent *Event)
return false;
}
-void cRegexp::PrintConfigLineToFile(FILE *f)
-{
- if (f) {
- if (source == REGEXP_UNDEFINED)
- fprintf(f, "%s\n", string);
- else
- fprintf(f, "%s%s\n", enabled ? "" : "!", string);
- }
-}
-
void cRegexp::ToggleEnabled(void)
{
if (source != REGEXP_UNDEFINED)
diff --git a/regexp.h b/regexp.h
index 4e00897..67270c2 100644
--- a/regexp.h
+++ b/regexp.h
@@ -10,8 +10,6 @@
#include "tools.h"
#include <vdr/epg.h>
-#include <vdr/tools.h>
-#include <stdio.h>
#ifdef HAVE_PCREPOSIX
#include <pcre.h>
@@ -31,14 +29,14 @@ private:
public:
cRegexp();
virtual ~cRegexp();
+ using cListItem::Apply;
virtual bool Apply(cEvent *Event);
void SetFromString(char *string, bool Enabled);
int GetSource() { return source; };
void ToggleEnabled(void);
- virtual void PrintConfigLineToFile(FILE *f);
};
// Global instance
-extern cEpgfixerList<cRegexp> EpgfixerRegexps;
+extern cEpgfixerList<cRegexp, cEvent> EpgfixerRegexps;
#endif //__EPGFIXER_REGEXP_H_
diff --git a/setup_menu.c b/setup_menu.c
index 1e5fc3f..2719115 100644
--- a/setup_menu.c
+++ b/setup_menu.c
@@ -8,21 +8,23 @@
#include "setup_menu.h"
#include <vdr/config.h>
#include <vdr/i18n.h>
-#include "tools.h"
+#include "blacklist.h"
#include "charset.h"
+#include "epgclone.h"
#include "regexp.h"
+#include "tools.h"
//--- cMenuSetupConfigEditor ------------------------------------------------------
#define MAXREGEXPLENGTH 512
-const char *RegexpChars =
- trNOOP(" abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789%~\\/?!()[]{}<>$^*.,:;-=#");
+const char *RegexpChars =
+ trNOOP("RegexpChars$ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789%~\\/?!()[]{}<>$^*.,:;-=#");
-template<class T> class cMenuSetupConfigEditor : public cMenuSetupPage
+template<class LISTITEM, class PARAMETER> class cMenuSetupConfigEditor : public cMenuSetupPage
{
private:
- cEpgfixerList<T> *list;
+ cEpgfixerList<LISTITEM, PARAMETER> *list;
const char *fileName;
char **lines;
char **numlines;
@@ -30,11 +32,11 @@ private:
{
lines = (char **)malloc(sizeof(char *)*(list->Count()));
int i = 0;
- T *item = (T *)list->First();
+ LISTITEM *item = (LISTITEM *)list->First();
while (item) {
lines[i] = (char *)malloc(sizeof(char)*MAXREGEXPLENGTH);
snprintf(lines[i], MAXREGEXPLENGTH, "%s", item->GetString());
- item = (T *)item->Next();
+ item = (LISTITEM *)item->Next();
++i;
}
}
@@ -53,10 +55,10 @@ private:
if (fileName && access(fileName, F_OK) == 0) {
FILE *f = fopen(fileName, "w");
if (f) {
- T *item = (T *)list->First();
+ LISTITEM *item = (LISTITEM *)list->First();
while (item) {
item->PrintConfigLineToFile(f);
- item = (T *)item->Next();
+ item = (LISTITEM *)item->Next();
}
fclose(f);
}
@@ -67,10 +69,10 @@ protected:
{
// Store regular expressions back to list
int i = 0;
- T *item = (T *)list->First();
+ LISTITEM *item = (LISTITEM *)list->First();
while (i < list->Count()) {
item->SetFromString(lines[i], item->Enabled());
- item = (T *)item->Next();
+ item = (LISTITEM *)item->Next();
++i;
}
}
@@ -78,17 +80,17 @@ protected:
{
Clear();
int i = 0;
- T *item = (T *)list->First();
+ LISTITEM *item = (LISTITEM *)list->First();
while (i < list->Count()) {
Add(new cMenuEditStrItem(item->Enabled() ? "+" : "-", lines[i], MAXREGEXPLENGTH, tr(RegexpChars)));
- item = (T *)item->Next();
+ item = (LISTITEM *)item->Next();
++i;
}
SetHelp(trVDR("Button$On/Off"), trVDR("Button$New"), trVDR("Button$Delete"), tr("Button$Cancel"));
Display();
}
public:
- cMenuSetupConfigEditor(cEpgfixerList<T> *l)
+ cMenuSetupConfigEditor(cEpgfixerList<LISTITEM, PARAMETER> *l)
{
list = l;
cEitFilter::SetDisableUntil(time(NULL) + 1000);
@@ -117,7 +119,7 @@ public:
case kGreen:
Store();
FreeArray();
- list->Add(new T());
+ list->Add(new LISTITEM());
LoadListToArray();
Set();
Display();
@@ -166,6 +168,10 @@ void cMenuSetupEpgfixer::Set(void)
help.Append(tr("Edit regular expressions."));
Add(new cOsdItem(tr("Character set conversions"), osUser2));
help.Append(tr("Edit character set conversions."));
+ Add(new cOsdItem(tr("EPG blacklists"), osUser3));
+ help.Append(tr("Edit EPG blacklists."));
+ Add(new cOsdItem(tr("EPG cloning"), osUser4));
+ help.Append(tr("Edit EPG data cloning."));
Add(new cOsdItem(tr("--- EPG bugfixes ---"), osUnknown, false));
help.Append("");
@@ -173,7 +179,7 @@ void cMenuSetupEpgfixer::Set(void)
Add(new cMenuEditBoolItem(tr("Remove quotes from ShortText"),
&newconfig.quotedshorttext));
help.Append(tr("EPG bugfix level >= 1: Some channels put the ShortText in quotes and use either the ShortText or the Description field, depending on how long the string is:\n\nTitle\n\"ShortText\". Description"));
- Add(new cMenuEditBoolItem(tr("Move Description from ShortText."),
+ Add(new cMenuEditBoolItem(tr("Move Description from ShortText"),
&newconfig.blankbeforedescription));
help.Append(tr("EPG bugfix level >= 1: Some channels put the Description into the ShortText (preceded by a blank) if there is no actual ShortText and the Description is short enough:\n\nTitle\n Description"));
Add(new cMenuEditBoolItem(tr("Remove repeated title from ShortText"),
@@ -232,6 +238,8 @@ eOSState cMenuSetupEpgfixer::ProcessKey(eKeys Key)
Skins.Message(mtInfo, tr("Loading configuration files..."));
EpgfixerRegexps.ReloadConfigFile();
EpgfixerCharSets.ReloadConfigFile();
+ EpgfixerBlacklists.ReloadConfigFile();
+ EpgfixerEpgClones.ReloadConfigFile();
Skins.Message(mtInfo, NULL);
state = osContinue;
break;
@@ -252,8 +260,12 @@ eOSState cMenuSetupEpgfixer::ProcessKey(eKeys Key)
}
}
else if (state == osUser1)
- return AddSubMenu(new cMenuSetupConfigEditor<cRegexp>(&EpgfixerRegexps));
+ return AddSubMenu(new cMenuSetupConfigEditor<cRegexp, cEvent>(&EpgfixerRegexps));
else if (state == osUser2)
- return AddSubMenu(new cMenuSetupConfigEditor<cCharSet>(&EpgfixerCharSets));
+ return AddSubMenu(new cMenuSetupConfigEditor<cCharSet, cEvent>(&EpgfixerCharSets));
+ else if (state == osUser3)
+ return AddSubMenu(new cMenuSetupConfigEditor<cBlacklist, cChannel>(&EpgfixerBlacklists));
+ else if (state == osUser4)
+ return AddSubMenu(new cMenuSetupConfigEditor<cEpgClone, cEvent>(&EpgfixerEpgClones));
return state;
}
diff --git a/tools.c b/tools.c
index c15c983..afc3848 100644
--- a/tools.c
+++ b/tools.c
@@ -6,6 +6,7 @@
*/
#include "tools.h"
+#include <vdr/thread.h>
//
// HTML conversion code taken from RSS Reader plugin for VDR
@@ -152,6 +153,81 @@ char *striphtml(char *str)
return NULL;
}
+// --- cAddEventThread ----------------------------------------
+
+class cAddEventListItem : public cListObject
+{
+protected:
+ cEvent *event;
+ tChannelID channelID;
+public:
+ cAddEventListItem(cEvent *Event, tChannelID ChannelID) { event = Event; channelID = ChannelID; }
+ tChannelID GetChannelID() { return channelID; }
+ cEvent *GetEvent() { return event; }
+ ~cAddEventListItem() { }
+};
+
+class cAddEventThread : public cThread
+{
+private:
+ time_t LastHandleEvent;
+ cList<cAddEventListItem> *list;
+protected:
+ virtual void Action(void);
+public:
+ cAddEventThread(void);
+ ~cAddEventThread(void) { list->cList::Clear(); }
+ void AddEvent(cEvent *Event, tChannelID ChannelID);
+};
+
+cAddEventThread::cAddEventThread(void)
+:cThread("add events to schedule")
+{
+ LastHandleEvent = time(NULL);
+ list = new cList<cAddEventListItem>;
+ SetPriority(19);
+}
+
+void cAddEventThread::Action(void)
+{
+ if (Running()) {
+ cAddEventListItem *e = list->First();
+ while (e) {
+ cAddEventListItem *d = NULL;
+ cSchedulesLock SchedulesLock(true, 10);
+ cSchedules *schedules = (cSchedules *)cSchedules::Schedules(SchedulesLock);
+ if (schedules) {
+ ((cSchedule *)schedules->GetSchedule(Channels.GetByChannelID(e->GetChannelID()), true))->AddEvent(e->GetEvent());
+ d = e;
+ }
+ e = list->Next(e);
+ if (d)
+ list->Del(d);
+ }
+ if (time(NULL) - LastHandleEvent > 10)
+ Cancel();
+ }
+}
+
+void cAddEventThread::AddEvent(cEvent *Event, tChannelID ChannelID)
+{
+ LastHandleEvent = time(NULL);
+ list->Add(new cAddEventListItem(Event, ChannelID));
+}
+
+static cAddEventThread AddEventThread;
+
+// ---
+
+void AddEvent(cEvent *Event, tChannelID ChannelID)
+{
+ if (!AddEventThread.Active())
+ AddEventThread.Start();
+ AddEventThread.AddEvent(Event, ChannelID);
+}
+
+// --- Listitem ----------------------------------------
+
cListItem::cListItem()
{
enabled = false;
@@ -205,7 +281,7 @@ bool cListItem::IsActive(tChannelID ChannelID)
bool found = false;
int i = 0;
while (i < numchannels) {
- if ((Channels.GetByChannelID(ChannelID)->Number() == GetChannelNum(i)) ||
+ if ((Channels.GetByChannelID(ChannelID)->Number() == GetChannelNum(i)) ||
(GetChannelID(i) && strcmp(*(ChannelID.ToString()), GetChannelID(i)) == 0)) {
found = true;
break;
@@ -239,9 +315,9 @@ int cListItem::LoadChannelsFromString(const char *string)
while (i < numchannels) {
// Use channel numbers
if (atoi(string))
- (channels_num)[i] = atoi(pc);
+ channels_num[i] = atoi(pc);
else// use channel IDs
- (channels_str)[i] = strdup(pc);
+ channels_str[i] = strdup(pc);
pc = strtok(NULL, ",");
++i;
}
@@ -254,3 +330,9 @@ void cListItem::ToggleEnabled(void)
{
enabled = !enabled;
}
+
+void cListItem::PrintConfigLineToFile(FILE *f)
+{
+ if (f)
+ fprintf(f, "%s%s\n", (!enabled && string && *string != '#') ? "!" : "", string);
+}
diff --git a/tools.h b/tools.h
index bf49fac..ebeeb76 100644
--- a/tools.h
+++ b/tools.h
@@ -17,6 +17,8 @@
#define FREE(x) { free(x); x = NULL; }
+void AddEvent(cEvent *event, tChannelID ChannelID);
+
char *striphtml(char *str);
class cListItem : public cListObject
@@ -35,62 +37,76 @@ protected:
public:
cListItem();
virtual ~cListItem();
+ virtual bool Apply(cChannel *Channel) { return 0; }
virtual bool Apply(cEvent *Event) { return 0; }
void SetFromString(char *string, bool Enabled);
const char *GetString() { return string; }
bool Enabled(void) { return enabled; }
void ToggleEnabled(void);
- virtual void PrintConfigLineToFIle(FILE *f) {}
+ void PrintConfigLineToFile(FILE *f);
};
-template<class T> class cEpgfixerList : public cList<T>
+template<class LISTITEM, class PARAMETER> class cEpgfixerList : public cList<LISTITEM>
{
protected:
char *fileName;
- bool LoadConfigFile(const char *FileName = NULL, bool AllowComments = true)
+ bool LoadConfigFile(bool AllowComments = true)
{
bool result = false;
- if (FileName && access(FileName, F_OK) == 0) {
- FILE *f = fopen(FileName, "r");
+ if (fileName && access(fileName, F_OK) == 0) {
+ FILE *f = fopen(fileName, "r");
if (f) {
char *s;
+ int line = 0;
+ int count = 0;
cReadLine ReadLine;
+ cString logmsg("");
+ logmsg = cString::sprintf("%s%s loaded. Active lines:", *logmsg, fileName);
while ((s = ReadLine.Read(f)) != NULL) {
+ ++line;
if (!isempty(s)) {
- this->Add(new T());
- cList<T>::Last()->SetFromString(s, true);
+ this->Add(new LISTITEM());
+ cList<LISTITEM>::Last()->SetFromString(s, true);
+ if (cList<LISTITEM>::Last()->Enabled()) {
+ ++count;
+ logmsg = cString::sprintf("%s%s%i", *logmsg, count == 1 ? " " : ",", line);
+ }
}
}
fclose(f);
+ if (count == 0)
+ logmsg = cString::sprintf("%s none", *logmsg);
+ isyslog("%s", *logmsg);
}
else {
- LOG_ERROR_STR(FileName);
+ LOG_ERROR_STR(fileName);
result = false;
}
}
+ ;
return result;
}
public:
cEpgfixerList() { fileName = NULL; }
~cEpgfixerList() { free(fileName); }
- void Clear(void) { cList<T>::Clear(); }
+ void Clear(void) { cList<LISTITEM>::Clear(); }
bool ReloadConfigFile(bool AllowComments = true)
{
Clear();
- return LoadConfigFile(fileName, AllowComments);
+ return LoadConfigFile(AllowComments);
}
- bool Apply(cEvent *Event)
+ bool Apply(PARAMETER *Parameter)
{
int res = false;
- T *item = (T *)(cList<T>::First());
+ LISTITEM *item = (LISTITEM *)(cList<LISTITEM>::First());
while (item) {
if (item->Enabled()) {
- int ret = item->Apply(Event);
+ int ret = item->LISTITEM::Apply(Parameter);
if (ret && !res)
res = true;
}
- item = (T *)(item->Next());
+ item = (LISTITEM *)(item->Next());
}
return res;
}