summaryrefslogtreecommitdiff
path: root/Tools/epg2timers
diff options
context:
space:
mode:
Diffstat (limited to 'Tools/epg2timers')
-rw-r--r--Tools/epg2timers/README151
-rw-r--r--Tools/epg2timers/epg2timers.cxx578
-rw-r--r--Tools/epg2timers/epg_channel_names400
-rwxr-xr-xTools/epg2timers/get_merkliste.pl82
-rwxr-xr-xTools/epg2timers/loadvdr.pl89
-rwxr-xr-xTools/epg2timers/update_timers22
-rwxr-xr-xTools/epg2timers/update_timers.old24
7 files changed, 1251 insertions, 95 deletions
diff --git a/Tools/epg2timers/README b/Tools/epg2timers/README
new file mode 100644
index 0000000..53888b1
--- /dev/null
+++ b/Tools/epg2timers/README
@@ -0,0 +1,151 @@
+Overview.
+=========
+
+The 4 modules in this directory are designed to allow vdr timer
+programming via the http://tvtv.de web EPG (Electronic Program Guide).
+
+Once you have these modules properly configured and installed,
+you should be able to simply click on the things you want vdr
+to record in the http://tvtv.de web EPG and be done with it.
+Everything else can be handled automatically.
+
+
+
+Module description.
+===================
+
+The http://tvtv.de web EPG creates a so-called "merkliste"
+("a list of items to remember") containing all the broadcasts
+you selected.
+
+1. The perl script "get_merkliste.pl" transfers this "merkliste"
+ from the http://tvtv.de web site to a local file "merkliste.html".
+
+2. The C++ program "epg2timers" converts this HTML file into vdr's
+ timers.conf format.
+
+3. The perl script "loadvdr.pl" pumps these new timer entries
+ into a running vdr using telnet and the SVDRP protocol.
+
+4. The shell script "update_timers" implements the overall
+ control of the entire process.
+ It retrieves the latest merkliste from http://tvtv.de,
+ converts it to timers.conf format and sends the timer entries
+ to vdr.
+
+
+
+Configuration.
+==============
+
+get_merkliste.pl requires configuration of the "files_to_fetch"
+variable preset.
+Log in to your http://tvtv.de account and click on the "Bookmark"
+item in the "Setup" submenu of the "Mein Programm" side bar menu.
+This will open a window with a URL in the location field that ends
+with an ID value. Replace the xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+in the "files_to_fetch" variable preset with your ID value.
+If you are using an HTTP proxy, uncomment the line containing
+the $ua->proxy call and put your proxy details in.
+
+epg2timers.cxx allows various items to be configured, but it
+should work out of the box. See "tvtv.de channel names" below.
+
+update_timers must know where to find the get_merkliste.pl
+perl script and the compiled epg2timers binary. Both must be
+in a directory pointed to by the TOOLDIR variable.
+update_timers also must know where to find vdr's current
+channels.conf file. Put that into the CHANPATH.
+
+Depending on the price of your internet access, you may want to
+run update_timers more or less frequently. It may also be a good
+idea to run it at times where it is unlikely to interfere with
+your current use of vdr. Configure a crontab entry according to
+these personal preferences. Here is the entry I use:
+1 2 * * * /home/cko/bin/update_timers
+It runs update_timers only once a night at 02:01 a.m.
+
+
+Installation.
+=============
+Create your TOOLDIR directory if it does not already exist.
+Copy get_merkliste.pl and loadvdr.pl into it, compile epg2timers.cxx
+with the command:
+ g++ epg2timers.cxx -o epg2timers
+and move the epg2timers binary into the TOOLDIR directory.
+
+The get_merkliste.pl script requires certain packages to run.
+Besides of course perl, install perl-libwww-perl (at least
+that's the name on SuSE 7.2, it may have a different name in
+your distribution).
+
+If you have problems with SVDRP and loadvdr.pl, you may want to
+try out the update_timers.old script, which replaces the timers.conf
+file directly and kills vdr (assuming that it will be restarted
+by the runvdr script) to make vdr reload the timers.conf file.
+
+
+tvtv.de channel names.
+======================
+The file epg_channel_names contains the names of all channels
+currently (as of September 9, 2001) supported by the tvtv.de
+web EPG. The variable "channel_map" in epg2timers.cxx maps
+these names into PNRs (aka Service IDs). I have initialized
+this table with provider names converted from a d-box channel
+scan of Astra 19.2E, so the PNRs should be correct for that
+satellite, but most of the names propably aren't yet- I simply
+had not enough time yet to go through epg_channel_names
+and insert all its channel names at the proper places in the
+channel map. Consider the map supplied an example. ;-)
+If you fix any of the entries, please send me a patch.
+For my own humble purposes, the table works well as it is.
+Of course, your channels.conf must contain the matching
+PNRs (last field in each line).
+
+
+To Do.
+======
+These are just ideas. They MAY get implemented.
+If you want them to happen, contribute a patch. ;-)
+
+* Support vdr hierarchical directories (after vdr does)
+ by mapping the http://tvtv.de genre texts into
+ directory names.
+* start_time_safety_margin for epg2timers.
+
+
+Authors.
+========
+Carsten Koch: epg2timers.cxx, update_timers, this README file.
+
+Axel Gruber and
+Rolf Hakenes: get_merkliste.pl
+
+Peter Ahlert: loadvdr.pl
+
+
+Credits.
+========
+I am grateful (in chronological order) to
+
+* Klaus Schmidinger for his excellent vdr program and for
+ keeping an open mind in all directions.
+
+* Suse (my wife, not the Linux distributor ;-) for encouraging me to
+ write epg2timers in June 2000 and for her constant patience and support.
+
+* Andreas Steinhauser for periodically criticizing the epg2timers
+ "manual mode" until I came up with the idea to fully automatize it
+ and for contributing ideas.
+
+* Axel Gruber for reminding me half a year later, for pushing
+ the idea until it got implemented, for asking for new features
+ all the time and for contributing ideas.
+
+* Axel Gruber and Rolf Hakenes for contributing the get_merkliste.pl
+ perl script.
+
+* Peter Ahlert for contributing the loadvdr.pl perl script.
+
+
+Carsten, September 2001.
diff --git a/Tools/epg2timers/epg2timers.cxx b/Tools/epg2timers/epg2timers.cxx
index 07e8182..94e1c8a 100644
--- a/Tools/epg2timers/epg2timers.cxx
+++ b/Tools/epg2timers/epg2timers.cxx
@@ -1,13 +1,13 @@
/*
- * epg2timers.cxx: Convert an EPG "merkliste" page (http://www.tvtv.de) to a timers.conf
- * file for Klaus Schmidinger's vdr (http://www.cadsoft.de/people/kls/vdr).
+ * epg2timers.cxx: Convert an EPG "merkliste" HTML page (http://tvtv.de)
+ * to timers.conf format for Klaus Schmidinger's vdr
+ * (http://www.cadsoft.de/people/kls/vdr).
*
- * Copyright (C) 2000 Carsten Koch
+ * Copyright (C) 2000, 2001 Carsten Koch
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
+ * version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -23,65 +23,349 @@
*/
+#include <malloc.h>
#include <stdio.h>
#include <string.h>
+#include <unistd.h>
+// User-configurable options.
-static const char date_line[] = "\t<td align=center valign=middle colspan=3><span id=fb-b10>";
-static const char start_time_line[] = " \t\t<td bgcolor=\"#7f98bf\" align=center><span id=\"fb-w14\"><nobr>&nbsp;";
-static const char stop_time_line[] = "\t\t\t<tr><td bgcolor=\"#002b64\" align=center><span id=\"fn-w9\">bis ";
-static const char channel_line[] = "\t\t\t<tr><td bgcolor=\"#002b64\" align=center><span id=\"fb-w9\">";
-static const char title_line[] = "\t\t\t\t<td bgcolor=\"#002b64\" align=left width=100%><span id=\"fb-w10\">";
-static const char summary_line[] = "\t\t\t<table border=0 cellpadding=10 cellspacing=0 bgcolor=\"white\" width=100%>";
-static const char * const channel_names[] =
+static const int stop_time_safety_margin = 10; // add 10 minutes to stop time in case start was delayed
+static const int recording_priority = 50; // vdr recording priority setting for all timer entries generated
+static const int recording_lifetime = 98; // vdr recording life time setting for all timer entries generated
+
+
+// Usually, you should not want to change any of these.
+
+static const int max_title = 256; // maximum length+1 of title file name generated
+static const int max_genre = 32; // maximum length+1 of genre text parsed
+static const int max_line = 1024; // line buffer (not used when parsing summary text)
+static const int max_summary = 9000; // Summary can be up to 9000 bytes long (a bit shorter than vdr's SVDRP command buffer)
+static const int max_vdr_channel = 1000; // maximum size+1 of your channels.conf
+
+// The following table maps http://tvtv.de channel names into Astra 19.2E PIDs.
+// It is incomplete. Contributions welcome.
+
+typedef struct
{
-"3sat",
-"ARTE",
-"*B1 Berlin",
-"BR3",
-"Bloomberg TV",
-"BR Alpha",
-"CNN",
-"ARD",
-"*DW-tv",
-"Eins Extra",
-"Eins Festival",
-"Eins MuXx",
-"euroNEWS",
-"HR3",
-"Kabel1",
-"Kinderkanal",
-"MDR",
-"MTV",
-"NDR",
-"NTV",
-"ORB",
-"*ORF1",
-"Phoenix",
-"PRO7",
-"RTL",
-"RTL2",
-"SAT1",
-"skynews",
-"SWF",
-"Super RTL",
-"TM3",
-"TW1",
-"VOX",
-"WDR",
-"Theaterkanal",
-"ZDF",
-"ZDF.doku",
-"ZDF.info",
-""
+ const char * tvtv_name;
+ unsigned short pnr;
+} map_entry;
+
+
+static const map_entry channel_map[] =
+{
+ // Deutschsprachig
+ {"13th Street", 42},
+ {"3sat", 28007},
+ {"ARTE", 28109},
+ {"B1", 28206},
+ {"BR3", 28107},
+ {"BR-alpha", 28112},
+ {"ARD", 28106},
+ {"Discovery", 14},
+ {"Disney Channel", 34},
+ {"Eins Extra", 28201},
+ {"Eins Festival", 28202},
+ {"Eins MuXx", 28203},
+ {"Filmpalast", 516},
+ {"FOX KIDS", 28},
+ {"Heimatkanal", 517},
+ {"HR", 28108},
+ {"Junior", 19},
+ {"Kabel 1", 899},
+ {"Kinderkanal", 28008},
+ {"Krimi&Co", 23},
+ {"K-Toon", 12},
+ {"Liberty TV.com", 12199},
+ {"MDR", 28204},
+ {"NDR", 28224},
+ {"NEUN LIVE", 897},
+ {"ORB", 28205},
+ {"ORF1", 13001},
+ {"ORF2", 13002},
+ {"Phoenix", 28114},
+ {"Planet", 13},
+ {"Premiere 1", 10},
+ {"Premiere 2", 11},
+ {"Premiere 3", 43},
+ {"Premiere Action", 20},
+ {"Premiere Comedy", 29},
+ {"Premiere SCI-FI", 41},
+ {"Premiere Star", 9},
+ {"PREMIERE WORLD", 8},
+ {"ProSieben", 898},
+ {"RTL", 12003},
+ {"RTL2", 12020},
+ {"SAT.1", 46},
+ {"SeaSonS", 33},
+ {"SR", 28110},
+ {"Studio Universal", 36},
+ {"Sunset", 16},
+ {"Super RTL", 12040},
+ {"Test-Z1", 28305},
+ {"TW1", 13013},
+ {"Via 1 - Schöner Reise", 44},
+ {"VOX", 12060},
+ {"WDR", 28111},
+ {"ZDF", 28006},
+ {"ZDF.doku", 28014},
+ {"ZDF.info", 28011},
+ // Movies
+ {"AXN", 29506},
+ {"CANAL+", 29100},
+ {"CANAL+ AZUL", 29101},
+ {"CANAL+ ROJO", 29102},
+ {"CANAL+ VERT", 8208},
+ {"CANAL+ 16/9", 8204},
+ {"CANAL+ 16|9", 29024},
+ {"C+ROOD", 4005},
+ {"CINE CINEMA I", 8206},
+ {"CINE CINEMA II", 8002},
+ {"CINE CINEMA III", 8003},
+ {"CINE CLASSICS", 8709},
+ {"CINE CINEMA 16/9", 8301},
+ {"cinecinemas", 4008},
+ {"CINECLASSICS", 29203},
+ {"Cinedom 1", 176},
+ {"Cinedom 1B", 178},
+ {"Cinedom 1C", 180},
+ {"Cinedom 1D", 190},
+ {"Cinedom 2", 179},
+ {"Cinedom 2B", 183},
+ {"Cinedom 2C", 184},
+ {"Cinedom 2D", 188},
+ {"Cinedom 2E", 193},
+ {"Cinedom 3", 182},
+ {"Cinedom 3B", 185},
+ {"Cinedom 3C", 192},
+ {"Cinedom 3D", 195},
+ {"Cinedom 4", 181},
+ {"Cinedom 4B", 187},
+ {"Cinedom 4C", 191},
+ {"Cinedom 5", 186},
+ {"Cinedom 5B", 194},
+ {"Cindedom Deluxe", 189},
+ {"CINEMANÍA AZUL", 29501},
+ {"CINEMANÍA ROJO", 29605},
+ {"CINEMANÍA", 29500},
+ {"K1", 8401},
+ {"K2", 8402},
+ {"K3", 8403},
+ {"K4", 8404},
+ {"K5", 8405},
+ {"K6", 8406},
+ {"K7", 8407},
+ {"K9", 8409},
+ {"K12", 8412},
+ {"TAQUILLA 1", 29206},
+ {"TAQUILLA 2", 29207},
+ {"TAQUILLA 3", 29502},
+ {"TAQUILLA 4", 29503},
+ {"TAQUILLA 5", 29504},
+ {"TAQUILLA 6", 29301},
+ {"TAQUILLA 7", 29302},
+ {"TAQUILLA 8", 29303},
+ {"TAQUILLA 11", 29316},
+ {"TAQUILLA 12", 29610},
+ {"TAQUILLA 13", 29402},
+ {"TAQUILLA 14", 29212},
+ {"TAQUILLA 16|9", 29606},
+ // Music
+ {"40 LATINO", 29031},
+ {"40 TV", 29110},
+ {"CANAL+ JAUNE", 8203},
+ {"CLASSICA", 15},
+ {"GOLDSTAR TV", 518},
+ {"MCM 2", 8305},
+ {"MCM AFRICA", 8307},
+ {"MCM", 8302},
+ {"MTV 2", 28649},
+ {"MTV 6", 28641},
+ {"MTV Base", 28645},
+ {"MTV Central", 28643},
+ {"MTV F", 28642},
+ {"MTV Hits", 28644},
+ {"MUZZIK", 8007},
+ {"RFM TV", 17008},
+ {"TMF", 5015},
+ {"VH1 Classic", 28647},
+ {"VH1", 28646},
+ {"Video Italia", 12220},
+ {"VIVA ZWEI", 12120},
+ {"VIVA", 12732},
+ {"ZIK'/XXL", 17004},
+ // News
+ {"BBC WORLD", 17007},
+ {"Bloomberg TV", 12160},
+ {"CNBC", 28010},
+ {"CNBC", 35},
+ {"CNBC-NBC", 29202},
+ {"CNN", 28512},
+ {"DW-tv", 9005},
+ {"EuroNews", 28015},
+ {"FOX NEWS", 29032},
+ {"N24", 47},
+ {"n-tv", 12730},
+ {"Sky News", 3995},
+ // Netherlands
+ {"NED1", 4011},
+ {"NED2", 4012},
+ {"NED3", 4013},
+ {"NET5", 5004},
+ {"RTL4", 2004},
+ {"RTL5", 2005},
+ {"SBS6", 5005},
+ {"V8/Fox Kids", 5020},
+ {"Yorin", 5010},
+ // Porn
+ {"BEATE-UHSE.TV", 21},
+ {"Blue Movie1", 513},
+ {"Blue Movie2", 514},
+ {"Blue Movie3", 515},
+ {"K10", 8410},
+ {"TAQUILLA X", 29213},
+ {"TAQUILLA X", 29602},
+ {"TAQUILLA XX", 29607},
+ {"X-ZONE", 4009},
+ // Sports
+ {"C+BLAUW", 4006},
+ {"DSF", 900},
+ {"EUROSPORT", 8101},
+ {"Eurosport", 28009},
+ {"EUROSPORT", 29310},
+ {"EUROSPORTNEWS", 29037},
+ {"PATHE SPORT|", 8009},
+ {"PREMIERE SPORT 1", 17},
+ {"PREMIERE SPORT 2", 27},
+ {"SUPERDOM", 26},
+ // French
+ {"13EME RUE", 8703},
+ {"AB 1", 17001},
+ {"AB MOTEURS", 17000},
+ {"ACTION", 17010},
+ {"ALLOCINE TV", 8308},
+ {"ANIMAUX", 17002},
+ {"ARTE", 9009},
+ {"BLOOMBERG TV", 8004},
+ {"CA TV", 8610},
+ {"CANAL+", 8201},
+ {"CANAL+ BLEU", 8202},
+ {"CANAL J", 8108},
+ {"CANAL JIMMY", 8006},
+ {"CANALCLUB", 8812},
+ {"Cartoon Network", 28511},
+ {"CLUB TELEACHAT", 8303},
+ {"COMEDIE !", 8702},
+ {"CONTACT TV", 8804},
+ {"CUISINE.TV", 8112},
+ {"DEMAIN !", 8701},
+ {"DISNEY CHANNEL", 8207},
+ {"DT CSAT 10", 9159},
+ {"ENCYCLOPEDIA", 17003},
+ {"ESCALES", 17005},
+ {"EURONEWS", 8505},
+ {"FORUM", 8707},
+ {"FRANCE 2", 8801},
+ {"FRANCE 3", 8802},
+ {"GAME ONE", 8717},
+ {"i TELEVISION", 8010},
+ {"KIOSQUE", 8704},
+ {"KTO", 8304},
+ {"LA CHAINE METEO", 8008},
+ {"LA CINQUIEME", 8501},
+ {"LaChaîneHistoire", 17006},
+ {"LCI", 8107},
+ {"LCP", 8506},
+ {"L'EQUIPE TV", 8706},
+ {"LibertyTV.com", 12280},
+ {"MANGAS", 17011},
+ {"MONTECARLO TMC", 8102},
+ {"Motors TV", 12300},
+ {"NAT GEOGRAPHIC", 8310},
+ {"PAD", 8211},
+ {"PARIS PREMIERE", 8104},
+ {"PLANETE 2", 8507},
+ {"PLANETE", 8103},
+ {"PMU sur Canal+", 8210},
+ {"RFO SAT", 8708},
+ {"SANTE - VIE", 8110},
+ {"SEASONS", 8001},
+ {"TCM", 28515},
+ {"TEST CDN 1", 8616},
+ {"TEST CDN 3", 8627},
+ {"TiJi", 8309},
+ {"TV 5", 9001},
+ {"TV BREIZH", 8502},
+ {"TV Puls", 20601},
+ {"TV5 Europe", 12240},
+ {"VOYAGE", 8105},
+ // Spanish
+ {"ANDALUCÍA TV", 29011},
+ {"Bloomberg", 12721},
+ {"CALLE 13", 29609},
+ {"Canal Canarias", 29700},
+ {"Cartoon Network", 29314},
+ {"CNN+", 29020},
+ {"DISCOVERY", 29116},
+ {"DISNEY CHANNEL", 29111},
+ {"DOCUMANÍA", 29200},
+ {"ESTILO", 29305},
+ {"ETB", 29035},
+ {"FASHION TV", 29115},
+ {"FOX KIDS", 29209},
+ {"FOX", 29507},
+ {"MOSAICO", 29315},
+ {"MÉTEO", 29014},
+ {"Nat Geo Channel", 29034},
+ {"NICK-PARAMOUNT", 29312},
+ {"RTPI", 9006},
+ {"SEASONS", 29204},
+ {"TAQUILLA 0", 29205},
+ {"TCM.", 28516},
+ {"TVC INT.", 29701},
+ {"VIAJAR", 29306},
+ // Miscellaneous
+ {"Alice", 12200},
+ {"Canal Algerie", 9008},
+ {"CANALPRO TV", 8516},
+ {"ESC1 - EGYPTE", 9003},
+ {"FASHION TV.COM", 17009},
+ {"Home Shopping Euro", 45},
+ {"Home Shopping Euro", 40},
+ {"Kabel 1 Austria", 20004},
+ {"Kabel 1 Schweiz", 20003},
+ {"Polonia 1/Top Sho", 20366},
+ {"ProSieben A", 20002},
+ {"ProSieben Schweiz", 20001},
+ {"QVC GERMANY", 12100},
+ {"RAI 1", 9004},
+ {"REAL MADRID TV", 29019},
+ {"RealityTV", 20309},
+ {"RTL TELE Letzebuerg", 3994},
+ {"RTM - MAROC", 9002},
+ {"SÜDWEST BW", 28113},
+ {"SÜDWEST RP", 28231},
+ {"Super 1", 20364},
+ {"Travel", 28001},
+ {"TV7", 9007},
+ {"TV-NIEP II", 12740},
+ {"Wishline", 12320}
};
+
+
+// Nothing user-configurable below this line.
+
+static const char date_line[] = "\t<td align=center valign=middle colspan=3><span id=fb-b10>";
+static const char start_time_line[] = " \t\t<td id=\"jobview-box-date\" align=center><nobr>&nbsp;";
+static const char stop_time_line[] = "\t\t\t<tr><td id=\"line\" align=center><span id=\"fn-w9\">bis ";
+static const char channel_line[] = "\t\t\t<tr><td align=center><span id=\"fb-w9\">";
+static const char title_line[] = "\t\t\t\t<td align=left width=100%><span id=\"fb-w10\">";
+static const char summary_line[] = "<span id=\"fn-b8\">";
+static const char genre_line[] = "\t\t\t\t<td align=right valign=center nowrap><span id=\"fn-w10\">";
+
static const int month_lengths[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
-static const int max_channel = sizeof(channel_names)/sizeof(char *);
-static const int max_title = 50; // maximum length of title file name generated
-static const int max_line = 1024; // line buffer (not used when parsing summary text)
-static const int max_summary = 5000; // Summary can be up to 5000 bytes long
-static const int stop_time_safety_margin = 10; // add 10 minutes to stop time in case start was delayed
@@ -102,6 +386,10 @@ char map_special_char(const char * const word)
return 'Ü';
else if (strcmp(word, "szlig") == 0)
return 'ß';
+ else if (strcmp(word, "nbsp") == 0)
+ return ' ';
+ else if (strcmp(word, "amp") == 0)
+ return '&';
return ' ';
}
@@ -109,40 +397,52 @@ char map_special_char(const char * const word)
-void read_file_name(const char * const line, char * const file_name)
+void read_file_name_and_title(const char * const line, char * const file_name, char * const title)
{
int line_index = sizeof(title_line) - 1;
int title_index = 0;
- char ch = line[line_index++];
+ int file_name_index = 0;
+ char ch;
do
{
+ ch = line[line_index++];
if (ch == '&')
{
char word[10];
int i = 0;
while ((line[line_index + i] != ';') && (i < 9))
- word[i++] = line[line_index + i];
- word[i] = 0;
- ch = map_special_char(word);
- line_index += i;
+ {
+ word[i] = line[line_index + i]; i++;
+ }
+ if (line[line_index + i] == ';')
+ {
+ word[i] = 0;
+ ch = map_special_char(word);
+ line_index += i;
+ }
}
switch (ch)
{
- case 'ä': file_name[title_index++] = 'a'; file_name[title_index++] = 'e'; break;
- case 'ö': file_name[title_index++] = 'o'; file_name[title_index++] = 'e'; break;
- case 'ü': file_name[title_index++] = 'u'; file_name[title_index++] = 'e'; break;
- case 'Ä': file_name[title_index++] = 'A'; file_name[title_index++] = 'e'; break;
- case 'Ö': file_name[title_index++] = 'O'; file_name[title_index++] = 'e'; break;
- case 'Ü': file_name[title_index++] = 'U'; file_name[title_index++] = 'e'; break;
- case 'ß': file_name[title_index++] = 's'; file_name[title_index++] = 's'; break;
+ case 'ä': file_name[file_name_index++] = 'a'; file_name[file_name_index++] = 'e'; break;
+ case 'ö': file_name[file_name_index++] = 'o'; file_name[file_name_index++] = 'e'; break;
+ case 'ü': file_name[file_name_index++] = 'u'; file_name[file_name_index++] = 'e'; break;
+ case 'Ä': file_name[file_name_index++] = 'A'; file_name[file_name_index++] = 'e'; break;
+ case 'Ö': file_name[file_name_index++] = 'O'; file_name[file_name_index++] = 'e'; break;
+ case 'Ü': file_name[file_name_index++] = 'U'; file_name[file_name_index++] = 'e'; break;
+ case 'ß': file_name[file_name_index++] = 's'; file_name[file_name_index++] = 's'; break;
+ case ' ': file_name[file_name_index++] = '_'; break;
+ case '&':
+ file_name[file_name_index++] = 'u'; file_name[file_name_index++] = 'n'; file_name[file_name_index++] = 'd';
+ break;
default:
- if (((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')) || ((ch >= '0') && (ch <= '9')))
- file_name[title_index++] = ch;
+ if (((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')) || ((ch >= '0') && (ch <= '9')) || (ch == '-'))
+ file_name[file_name_index++] = ch;
}
- ch = int(line[line_index++]);
- } while ((title_index < max_title-1) && (ch != '<') && (ch != 0) && (line_index < max_line-1));
- file_name[title_index] = 0;
+ title[title_index++] = ch;
+ } while ((file_name_index < max_title-5) && (ch != '<') && (ch != 0));
+ file_name[file_name_index] = 0;
+ title[title_index-1] = 0;
}
@@ -184,7 +484,7 @@ void read_summary(char * const summary)
word[word_index++] = ch;
} while ((word_index < 6) && (ch != '>') && (ch != EOF));
while ((ch != '>') && (ch != EOF)) ch = getchar();
- if (strncmp("/table", word, 6) == 0)
+ if (strncmp("/span", word, 4) == 0)
done = true;
}
break;
@@ -207,62 +507,150 @@ void read_summary(char * const summary)
+int find_channel_number(const unsigned short * const vdr_pnrs, const char * const channel_name)
+
+{
+ for (int tvtv_channel_number = 0; tvtv_channel_number < sizeof(channel_map)/sizeof(map_entry); tvtv_channel_number++)
+ if (strcmp(channel_name, channel_map[tvtv_channel_number].tvtv_name) == 0)
+ for (int vdr_channel_number = 0; vdr_pnrs[vdr_channel_number] != 0xFFFF; vdr_channel_number++)
+ if (vdr_pnrs[vdr_channel_number] == channel_map[tvtv_channel_number].pnr)
+ return vdr_channel_number;
+ fprintf(stderr, "Error - channel '%s' not recognized.\n", channel_name);
+ exit(1);
+ /*NOTREACHED*/
+}
+
+
-main()
+unsigned short * read_vdr_pnrs(const char * const channels_conf_file_name)
+
{
- int channel = 0;
+ FILE * channels_conf = fopen(channels_conf_file_name, "r");
+ if (channels_conf == NULL)
+ {
+ perror("unable to open channels.conf.");
+ exit(1);
+ }
+ unsigned short * vdr_pnrs = (unsigned short *) malloc(max_vdr_channel * sizeof(unsigned short));
+ int vdr_channel_number = 0;
+ while (!feof(channels_conf) && (vdr_channel_number < max_vdr_channel-1))
+ {
+ char line[1024];
+ fgets(line, sizeof(line)-1, channels_conf);
+ int pnr;
+ if ((line[0] != ':') &&
+ (sscanf(line, "%*[^:]:%*[^:]:%*[^:]:%*[^:]:%*[^:]:%*[^:]:%*[^:]:%*[^:]:%*[^:]:%d", &pnr) == 1))
+ vdr_pnrs[vdr_channel_number++] = pnr;
+ }
+ vdr_pnrs[vdr_channel_number++] = 0xFFFF; // sentinel
+ fprintf(stderr, "%d pnrs.\n", vdr_channel_number);
+ return (unsigned short *) realloc(vdr_pnrs, vdr_channel_number * sizeof(unsigned short));
+}
+
+
+
+
+void process_input(const unsigned short * const vdr_pnrs)
+
+{
+
+ int channel = -1;
int day = -1;
int next_day = -1;
int start_time = -1;
- int stop_time = -1;
+ int stop_hour = -1;
+ int stop_minute= -1;
+ char genre[max_genre] = {0};
char summary[max_summary] = {0};
char file_name[max_title] = {0};
+ char title[max_title] = {0};
while (!feof(stdin))
{
char line[max_line];
fgets(line, max_line-1, stdin);
+ line[max_line-1] = 0;
if (strncmp(line, date_line, sizeof(date_line)-1) == 0)
{
const int month = (line[sizeof(date_line) + 6]- '0') * 10 + line[sizeof(date_line) + 7]-'0';
day = (line[sizeof(date_line) + 3]- '0') * 10 + line[sizeof(date_line) + 4]-'0';
- next_day = day == month_lengths[month]? 1 : day + 1;
+ next_day = day == month_lengths[month-1]? 1 : day + 1;
}
else if (strncmp(line, start_time_line, sizeof(start_time_line)-1) == 0)
- {
start_time = (line[sizeof(start_time_line) - 1] - '0') * 1000 +
(line[sizeof(start_time_line) ] - '0') * 100 +
(line[sizeof(start_time_line) + 2] - '0') * 10 +
(line[sizeof(start_time_line) + 3] - '0');
- }
else if (strncmp(line, stop_time_line, sizeof(stop_time_line)-1) == 0)
{
- stop_time = ((line[sizeof(stop_time_line) - 1] - '0') * 1000 +
- (line[sizeof(stop_time_line) ] - '0') * 100 +
- (line[sizeof(stop_time_line) + 2] - '0') * 10 +
- (line[sizeof(stop_time_line) + 3] - '0') + stop_time_safety_margin) % 2400;
- if ((day < 0) || (start_time < 0) || (file_name[0] == 0) || (channel == max_channel))
+ stop_hour = (line[sizeof(stop_time_line) - 1] - '0') * 10 +
+ (line[sizeof(stop_time_line) ] - '0');
+ stop_minute = (line[sizeof(stop_time_line) + 2] - '0') * 10 +
+ (line[sizeof(stop_time_line) + 3] - '0') +
+ stop_time_safety_margin;
+ if (stop_minute > 59)
+ {
+ stop_minute -= 60;
+ if (stop_hour == 23)
+ stop_hour = 0;
+ else
+ stop_hour++;
+ }
+ if ((day < 0) || (start_time < 0) || (file_name[0] == 0) || (channel == -1))
+ {
fprintf(stderr, "Input data error.\n");
+ exit(1);
+ }
else
- printf("1:%03d:%02d:%04d:%04d:2:7:%s:%s\n", channel+1, start_time < 600? next_day : day, start_time, stop_time, file_name, summary);
- start_time = -1; stop_time = -1; file_name[0] = 0; summary[0] = 0; channel = max_channel;
+ printf("1:%03d:%02d:%04d:%02d%02d:%d:%d:%s:\"%s\" %s||%s||||||(epg2timers)\n",
+ channel+1, start_time < 600? next_day : day, start_time, stop_hour, stop_minute,
+ recording_priority, recording_lifetime, file_name,
+ title, genre, summary);
+ start_time = -1; channel = -1;
+ file_name[0] = 0; summary[0] = 0; genre[0] = 0;
}
else if (strncmp(line, title_line, sizeof(title_line)-1) == 0)
- read_file_name(line, file_name);
+ read_file_name_and_title(line, file_name, title);
else if (strncmp(line, channel_line, sizeof(channel_line)-1) == 0)
{
int i = sizeof(channel_line);
- while ((i < max_line-1) && (line[i] != '<')) i++;
+ while ((line[i] != '<') && (line[i] != 0)) i++;
line[i] = 0; // end of string
- for (channel = 0; (channel < max_channel) &&
- (strcmp(line + sizeof(channel_line) - 1, channel_names[channel]) != 0);
- channel++);
- if (channel == max_channel)
- fprintf(stderr, "Error - channel '%s' not recognized.\n", line + sizeof(channel_line) - 1);
+ channel = find_channel_number(vdr_pnrs, line + sizeof(channel_line) - 1);
}
else if (strncmp(line, summary_line, sizeof(summary_line)-1) == 0)
read_summary(summary);
+ else if (strncmp(line, genre_line, sizeof(genre_line)-1) == 0)
+ {
+ int genre_index;
+ for (genre_index = 0; genre_index < max_genre-1; genre_index++)
+ {
+ const char ch = line[genre_index + sizeof(genre_line)-1];
+ if ((ch == 0) || (ch == '&') || (ch == '<'))
+ break;
+ genre[genre_index] = ch;
+ }
+ genre[genre_index] = 0;
+ }
}
}
+
+
+
+main(int argc, char *argv[])
+
+{
+ fprintf(stderr, "epg2timers Version 0.5, 15-Sep-2001.\n");
+
+ if (argc != 2)
+ {
+ fprintf(stderr, "usage: %s channels.conf\n", argv[0]);
+ exit(1);
+ }
+
+ const unsigned short * const vdr_pnrs = read_vdr_pnrs(argv[1]);
+ process_input(vdr_pnrs);
+ exit(0);
+}
diff --git a/Tools/epg2timers/epg_channel_names b/Tools/epg2timers/epg_channel_names
new file mode 100644
index 0000000..2633a99
--- /dev/null
+++ b/Tools/epg2timers/epg_channel_names
@@ -0,0 +1,400 @@
+ATV,at
+ORF1,at
+ORF2,at
+TW1,at
+
+Club RTL,be
+Ketnet/Canvas,be
+TVI,be
+tv1,be
+
+SF1,ch
+sf2,ch
+
+13th Street,de
+3sat,de,at,ch
+ARD,de
+ARTE,de
+B1,de
+BBC World,de
+BEATE-UHSE.TV,de
+BR-alpha,de
+BR3,de
+Bet on Jazz,de
+Bloomberg TV,de
+Blue Movie1,de
+Blue Movie2,de
+Blue Movie3,de
+CNBC,de
+CNN,de
+Cartoon,de
+Cindedom Deluxe,de
+Cinedom 1,de
+Cinedom 2,de
+Cinedom 3,de
+Cinedom 4,de
+Cinedom 5,de
+Classica,de
+DSF,de
+Discovery,de
+Disney Channel,de
+Eins Extra,de
+Eins Festival,de
+Eins MuXx,de
+EuroNews,de
+Eurosport,de
+FOX KIDS,de
+Filmpalast,de
+Goldstar TV,de
+HH-1,de
+HR,de
+Heimatkanal,de
+Junior,de
+K-Toon,de
+Kabel 1,de
+Kinderkanal,de
+Krimi&Co,de
+MDR,de
+MTV,de
+MTV2,de
+N24,de
+NBC,de
+NDR,de
+NEUN LIVE,de
+ONYX,de
+ORB,de
+Phoenix,de
+Planet,de
+Premiere 1,de
+Premiere 2,de
+Premiere 3,de
+Premiere Action,de
+Premiere Comedy,de
+Premiere SCI-FI,de
+Premiere Sport1,de
+Premiere Sport2,de
+Premiere Sport3,de
+Premiere Star,de
+Premiere analog,de
+ProSieben,de
+QVC,de
+RTL,de
+RTL2,de
+SAT.1,de
+SR,de
+SWR BW,de
+SWR RP,de
+SeaSonS,de
+Studio Universal,de
+Sunset,de
+Super RTL,de
+TNT,de
+TRT,de,tr
+TV.BERLIN,de
+Theaterkanal,de
+VIVA,de
+VIVA2,de
+VOX,de
+WDR,de
+ZDF,de
+ZDF.doku,de
+ZDF.info,de
+n-tv,de
+skynews,de
+tv.m,de
+
+Danmark 1,dk
+TV2 Danmark,dk
+
+MTV3,fi
+Nelonen 4,fi
+Subtv,fi
+TV1,fi
+TV2,fi
+
+13ème Rue,fr
+AB 1,fr
+Arte,fr
+Arte Sat,fr
+Canal J,fr
+Canal Jimmy,fr
+Canal+,fr
+Canal+ Bel. bleu,fr
+Canal+ Bel. jaune,fr
+Canal+ Belgique,fr
+Canal+ bleu,fr
+Canal+ jaune,fr
+Canal+ vert,fr
+Ciné Cinémas 1,fr
+Ciné Cinémas 2,fr
+Ciné Cinémas 3,fr
+Ciné Classics,fr
+Cinéfaz,fr
+Cinéstar 1,fr
+Cinéstar 2,fr
+Cinétoile,fr
+Comédie !,fr
+Disney Channel,fr
+Escale,fr
+Eurosport,fr
+Festival,fr
+Fox Kids,fr
+France 2,fr
+France 3,fr
+Histoire,fr
+LCI,fr
+La Cinquième Sat,fr
+La chaîne histoire,fr
+La cinquième,fr
+M6,fr
+M6 Music,fr
+MCM,fr
+MTV,fr
+Mangas,fr
+Mezzo,fr
+Muzzik,fr
+Odyssée,fr
+Paris Première,fr
+Pathé sport,fr
+Planète,fr
+RTBF 1,fr
+RTBF 2,fr
+RTL 9,fr
+Série Club,fr
+TCM,fr
+TF1,fr
+TMC,fr
+TSR 1,fr
+TSR 2,fr
+TV5,fr
+Télétoon,fr
+Téva,fr
+Voyage,fr
+XXL,fr
+
+ANIMALplanet,hu
+Budapest TV,hu
+Duna TV,hu
+FILMMÚZEUM,hu
+FOX KIDS/SPORTS,hu
+FÕNIX TV,hu
+Game Channel,hu
+HBO,hu
+Hallmark,hu
+MAGYAR ATV,hu
+Minimax,hu
+National Geographic,hu
+Nickelodeon,hu
+RTL Klub,hu
+Romantica,hu
+SATeLIT,hu
+SPORT1,hu
+Spektrum TV,hu
+TV2,hu
+VIASAT3,hu
+VIVA+,hu
+fix.tv,hu
+m1,hu
+m2,hu
+
++ Calcio,it
++ F1,it
+Adult +,it
+CANALE 5,it
+Canal Jimmy,it
+Canale Viaggi,it
+Cartoon Network,it
+Cine Classics,it
+CineCinemas 1,it
+CineCinemas 2,it
+Classica,it
+Cult Network,it
+Discovery Channel,it
+Disney Channel,it
+Euro News,it
+Eurosport,it
+Hallmark,it
+Happy Channel,it
+ITALIA 1,it
+La 7,it
+MTV,it
+MTV - TMC 2,it
+Marcopolo,it
+Match Music,it
+Milan Channel,it
+Nuvolari Motor,it
+Odeon,it
+Planete,it
+Primafila,it
+RAI 1,it
+RAI 2,it
+RAI 3,it
+RAI Sat Fiction,it
+RETE 4,it
+Raisat Album,it
+Raisat Art,it
+Raisat Cinema,it
+Raisat Educational,it
+Raisat Gambero Rosso,it
+Raisat Nettuno 1,it
+Raisat Nettuno 2,it
+Raisat Ragazzi,it
+Raisat Show,it
+Raisat Sport,it
+SNAI Sat,it
+Salute e benessere,it
+Sat 2000,it
+Satisfation Club TV,it
+Seasons,it
+Stream Calcio,it
+Stream News,it
+Studio Universal,it
+TSI 1,it
+TSI 2,it
+TVL,it
+Tele+ 16:9,it
+Tele+ Bianco,it
+Tele+ Grigio,it
+Tele+ Nero,it
+VIVA - Rete A,it
+
+Netherland 1,nl
+Netherland 2,nl
+Netherland 3,nl
+
+ATV Avrupa,tr
+Kanal D,tr
+Kral TV,tr
+NTV Turkey,tr
+Show TV,tr
+Star TV,tr
+
+Adult Channel,uk
+Adventure One,uk
+Anglia,uk
+BBC Choice,uk
+BBC Choice NI,uk
+BBC Choice Scotland,uk
+BBC Choice Wales,uk
+BBC Knowledge,uk
+BBC News 24,uk
+BBC Parliament,uk
+BBC Prime,uk
+BBC World,uk
+BBC1,uk
+BBC1 North. Ireland,uk
+BBC1 Scotland,uk
+BBC1 Wales,uk
+BBC2,uk
+BBC2 North. Ireland,uk
+BBC2 Scotland,uk
+BBC2 Wales,uk
+Bangla TV,uk
+Bloomberg TV,uk
+Border,uk
+Bravo (Analogue),uk
+Bravo (Digital),uk
+British Eurosport,uk
+CNBC Europe,uk
+CNN,uk
+Carlton Central,uk
+Carlton Cinema,uk
+Carlton Food,uk
+Carlton Westcountry,uk
+Carlton/LWT,uk
+Cartoon Network,uk
+Challenge TV,uk
+Channel 4,uk
+Channel 5,uk
+Channel Television,uk
+Disc. Animal Planet,uk
+Disc. Channel (Ana.),uk
+Disc. Civilisations,uk
+Disc. Home Leisure,uk
+Disc. Sci-Trek,uk
+Disc. Travel Advent.,uk
+Discovery Channel,uk
+Discovery Kids,uk
+Discovery Wings,uk
+Disney,uk
+Euronews,uk
+Fantasy Ch. Dig.,uk
+Fantasy Channel,uk
+Film Four,uk
+Fox Kids,uk
+Grampian,uk
+Granada,uk
+Granada Breeze,uk
+Granada Men & Motors,uk
+Granada Plus,uk
+HTV Wales,uk
+HTV West,uk
+Hallmark,uk
+History Channel,uk
+ITN News Channel,uk
+ITV Sport Channel,uk
+ITV Sport Plus,uk
+ITV2,uk
+Landscape,uk
+Living,uk
+MTV UK,uk
+MUTV,uk
+Meridian,uk
+National Geographic,uk
+Network 2,uk
+Nick Junior,uk
+Nick Junior Analogue,uk
+Nickelodeon (dig.),uk
+Nickleodeon (ana.),uk
+Pakistani Channel,uk
+Paramount Comedy,uk
+Performance,uk
+Play UK,uk
+Playboy TV,uk
+QVC,uk
+RTE1,uk
+Racing Channel,uk
+Rapture TV,uk
+S2,uk
+S4C,uk
+S4C digidol,uk
+SKY Cinema,uk
+SKY Movie Max(SDig.),uk
+SKY Movie Max(ana.),uk
+SKY News,uk
+SKY Premier(Digital),uk
+SKY Premier(OnDigi),uk
+SKY Sports 1,uk
+SKY Sports 2,uk
+SKY Sports 3,uk
+Sci-Fi Cable,uk
+Sci-Fi Satelite,uk
+Scottish,uk
+Screenshop,uk
+Shop!,uk
+Sky Movie Max(OnDig),uk
+Sky One,uk
+Sky One (OnDigital),uk
+Sky Premier(Ana.),uk
+Sky Sports .com,uk
+Sky Sports Extra,uk
+Sky Travel,uk
+Sony Entertainment,uk
+TCM,uk
+TCM (Analogue),uk
+TG4,uk
+TV3,uk
+Tara Television,uk
+The Box,uk
+Trouble Analogue,uk
+Trouble Digital,uk
+Tyne Tees Television,uk
+UK Drama,uk
+UK Gold,uk
+UK Gold 2,uk
+UK Horizons,uk
+UK Style,uk
+Ulster ,uk
+VH1,uk
+Yorkshire,uk
+Zee TV,uk
diff --git a/Tools/epg2timers/get_merkliste.pl b/Tools/epg2timers/get_merkliste.pl
new file mode 100755
index 0000000..bb23fa3
--- /dev/null
+++ b/Tools/epg2timers/get_merkliste.pl
@@ -0,0 +1,82 @@
+#!/usr/bin/perl
+# Create a user agent object
+
+use HTML::Entities;
+use HTML::Parser;
+use LWP::UserAgent;
+use IO::Handle;
+
+STDOUT->autoflush(1);
+
+$ua = new LWP::UserAgent;
+$ua->agent("Mozilla/9.1 " . $ua->agent);
+# $ua->proxy('http', 'http://localhost:8080/');
+
+$filename = "merkliste.html";
+$base_url = "http://www.tvtv.de";
+# Hier das Bookmark von TVTV eintragen:
+@files_to_fetch = ("/cgi-bin/bookmark.cgi?id=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+$num = 0;
+$state = 0;
+
+$p = HTML::Parser->new( api_version => 3,
+ start_h => [\&fparser_start, "tagname, attr"],
+ unbroken_text => 1 );
+
+foreach $url (@files_to_fetch) {
+ $nurl = $base_url . $url;
+ print "Getting " . $nurl . "...\n";
+ $req = new HTTP::Request GET => $nurl;
+ $res = $ua->request($req);
+ if ($res->is_success) {
+ open (OUTFILE, ">" . $filename);
+ print OUTFILE $res->content;
+ close (OUTFILE);
+ $p->parse ($res->content);
+ $p->eof;
+ } else {
+ print "...FAILED\n";
+ }
+}
+# Zielordner fuer die Speicherung der Merkliste:
+
+print "...saved to 'merkliste.html'\n";
+sub fparser_start {
+ my($tagname, $attr_t) = @_;
+ my(%attr) = %$attr_t;
+
+ if ($tagname eq "frame") {
+ if ($state == 1) {
+ if (($attr{name} eq "frame_main") ||
+ ($attr{name} eq "frame_nav") ||
+ ($attr{name} eq "frame_nav_bottom")) {
+ push @files_to_fetch, $attr{src};
+ }
+ }
+ if ($state == 2) {
+ if (($attr{name} eq "frame_content")) {
+ push @files_to_fetch, $attr{src};
+ }
+ }
+ }
+ if ($tagname eq "a") {
+ if ($attr{href} ne "") {
+ $last_href = $attr{href};
+ if ($state == 0) {
+ push @files_to_fetch, $last_href;
+ $state = 1;
+ }
+ }
+ }
+ if ($tagname eq "img") {
+ if ($state == 1) {
+ if ($attr{src} =~ /b_joblist/i) {
+ $state = 2;
+ push @files_to_fetch, $last_href;
+ }
+ }
+ }
+}
+
+
diff --git a/Tools/epg2timers/loadvdr.pl b/Tools/epg2timers/loadvdr.pl
new file mode 100755
index 0000000..485b0a4
--- /dev/null
+++ b/Tools/epg2timers/loadvdr.pl
@@ -0,0 +1,89 @@
+#!/usr/bin/perl
+#
+# 0.01 loadvdr (peter)
+# 0.02 delete old entries before updating (peter)
+# 0.03 dumped Net::Telnet because of lost connections
+#
+# please submit diffs to petera@gmx.net
+#
+# ./epg2timers < merkliste.html | perl -w loadvdr.pl
+#
+#
+
+use Socket;
+use Getopt::Std;
+
+@resp = ();
+
+$Dest = "localhost";
+$Port = 2001;
+
+$Timeout = 10; # max. seconds to wait for response
+
+$SIG{ALRM} = sub { Error("timeout"); };
+alarm($Timeout);
+
+$iaddr = inet_aton($Dest) || Error("no host: $Dest");
+$paddr = sockaddr_in($Port, $iaddr);
+
+$proto = getprotobyname('tcp');
+socket(SOCK, PF_INET, SOCK_STREAM, $proto) || Error("socket: $!");
+connect(SOCK, $paddr) || Error("connect: $!");
+select(SOCK); $| = 1;
+Receive_void();
+
+Send("lstt");
+
+foreach $item (reverse @resp){
+ if ($item =~ /^250.(\d{1,2}).*\(epg2timers\)/) {
+ Send_void("DELT $1");
+ }
+}
+
+while (defined ($line = <STDIN>)) {
+ chomp $line;
+ Send_void("UPDT $line");
+}
+
+Send("quit");
+close(SOCK) || Error("close: $!");
+
+
+
+sub Send
+{
+ my $cmd = shift || Error("no command to send");
+ print SOCK "$cmd\r\n";
+ Receive();
+}
+
+sub Send_void
+{
+ my $cmd = $_[0];
+ print SOCK "$cmd\r\n";
+ Receive_void();
+}
+
+sub Receive
+{
+ while (<SOCK>) {
+ chomp;
+ push @resp,$_;
+ last if substr($_, 3, 1) ne "-";
+ }
+}
+
+sub Receive_void
+{
+ while (<SOCK>) {
+ last if substr($_, 3, 1) ne "-";
+ }
+}
+
+sub Error
+{
+ print STDERR "@_\n";
+ close(SOCK);
+ exit 0;
+}
+
diff --git a/Tools/epg2timers/update_timers b/Tools/epg2timers/update_timers
new file mode 100755
index 0000000..3849841
--- /dev/null
+++ b/Tools/epg2timers/update_timers
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+# update_timers: retrieve a new "merkliste" from http://tvtv.de,
+# convert it to vdr format and transmit it to vdr via SVDRP.
+
+TOOLDIR="/home/cko/bin"
+CHANPATH="/home/cko/VDR/channels.conf"
+
+cd /tmp
+rm -f merkliste.html
+
+# if you have a slow dial up connection to your name server and/or ISP,
+# this will avoid a timeout in get_merkliste.pl.
+ping -c 2 www.tvtv.de
+
+# get the "merkliste".
+$TOOLDIR/get_merkliste.pl
+
+if [ -s merkliste.html ] ; then
+ # convert merkliste.html to timers.conf format and transmit it to vdr.
+ $TOOLDIR/epg2timers $CHANPATH < merkliste.html | $TOOLDIR/loadvdr.pl
+fi
diff --git a/Tools/epg2timers/update_timers.old b/Tools/epg2timers/update_timers.old
new file mode 100755
index 0000000..c4c3f5c
--- /dev/null
+++ b/Tools/epg2timers/update_timers.old
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+# update_timers: load a new "merkliste" from http://tvtv.de
+# and create a new VDR timer configuration file (timers.conf)
+# from it. Restart VDR if the timers have changed.
+
+TOOLDIR="/home/cko/bin"
+VDRDIR="/home/cko/VDR"
+
+cd /tmp
+rm -f merkliste.html epgtimers.new epgtimers.old vdrtimers.old
+ping -c 2 www.tvtv.de
+$TOOLDIR/get_merkliste.pl
+if [ -s merkliste.html ] ; then
+ $TOOLDIR/epg2timers $VDRDIR/channels.conf < merkliste.html | sort -t: +2.0 -5.0 > epgtimers.new
+ fgrep '(epg2timers)' $VDRDIR/timers.conf | sort -t: +2.0 -5.0 > epgtimers.old
+ if ! cmp -s epgtimers.old epgtimers.new ; then
+ /sbin/killproc $VDRDIR/vdr
+ fgrep -v '(epg2timers)' $VDRDIR/timers.conf > vdrtimers.old
+ cat epgtimers.new vdrtimers.old | sort -t: +2.0 -5.0 > $VDRDIR/timers.conf
+ echo "Timers updated."
+ fi
+fi
+rm -f merkliste.html epgtimers.new epgtimers.old vdrtimers.old