diff options
author | Matti Lehtimäki <matti.lehtimaki@gmail.com> | 2012-05-12 14:42:01 +0300 |
---|---|---|
committer | Matti Lehtimäki <matti.lehtimaki@gmail.com> | 2012-05-12 14:42:01 +0300 |
commit | 6b488dcedf24cf9b4890505eba992d683eedecac (patch) | |
tree | 51347d76c4b2891568e54348d9ce0ab99304bd0b | |
parent | 548e0a6bc35d4c776039f7467c0d67eabf9ef46a (diff) | |
download | vdr-plugin-epgfixer-6b488dcedf24cf9b4890505eba992d683eedecac.tar.gz vdr-plugin-epgfixer-6b488dcedf24cf9b4890505eba992d683eedecac.tar.bz2 |
Support for ignoring and copying EPG data. Bug fixes.
Fix character set conversion for selected channels. Fix and improve Makefile (thanks to Ville Skyttä and Rolf Ahrenberg). Fix compiling with g++-4.7.
-rw-r--r-- | HISTORY | 9 | ||||
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | README | 31 | ||||
-rw-r--r-- | blacklist.c | 36 | ||||
-rw-r--r-- | blacklist.h | 27 | ||||
-rw-r--r-- | charset.c | 48 | ||||
-rw-r--r-- | charset.h | 9 | ||||
-rw-r--r-- | epgclone.c | 91 | ||||
-rw-r--r-- | epgclone.h | 31 | ||||
-rw-r--r-- | epgfixer.c | 41 | ||||
-rw-r--r-- | epgfixer/blacklist.conf | 3 | ||||
-rw-r--r-- | epgfixer/charset.conf | 10 | ||||
-rw-r--r-- | epgfixer/epgclone.conf | 2 | ||||
-rw-r--r-- | epghandler.c | 14 | ||||
-rw-r--r-- | epghandler.h | 2 | ||||
-rw-r--r-- | po/fi_FI.po | 24 | ||||
-rw-r--r-- | regexp.c | 13 | ||||
-rw-r--r-- | regexp.h | 6 | ||||
-rw-r--r-- | setup_menu.c | 48 | ||||
-rw-r--r-- | tools.c | 88 | ||||
-rw-r--r-- | tools.h | 44 |
21 files changed, 481 insertions, 98 deletions
@@ -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. @@ -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) @@ -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_ @@ -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); -} @@ -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_ @@ -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 "" @@ -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) @@ -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; } @@ -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); +} @@ -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; } |