summaryrefslogtreecommitdiff
path: root/Tools
diff options
context:
space:
mode:
Diffstat (limited to 'Tools')
-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
-rw-r--r--Tools/master-timer/LIESMICH154
-rw-r--r--Tools/master-timer/README54
-rw-r--r--Tools/master-timer/THANKS18
-rw-r--r--Tools/master-timer/Todo4
-rwxr-xr-xTools/master-timer/convert-DTV2VDR.pl151
-rwxr-xr-xTools/master-timer/convert-oldtorecord.pl61
-rwxr-xr-xTools/master-timer/master-timer.pl2231
-rw-r--r--Tools/master-timer/sample/channels-to-scan4
-rw-r--r--Tools/master-timer/sample/config38
-rw-r--r--Tools/master-timer/sample/convert-channel-list26
-rw-r--r--Tools/master-timer/sample/deepblack251
-rw-r--r--Tools/master-timer/sample/subtitle-movie11
-rw-r--r--Tools/master-timer/sample/torecord116
20 files changed, 3132 insertions, 1333 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
diff --git a/Tools/master-timer/LIESMICH b/Tools/master-timer/LIESMICH
index 9694875..8e53da9 100644
--- a/Tools/master-timer/LIESMICH
+++ b/Tools/master-timer/LIESMICH
@@ -1,106 +1,70 @@
- Master-Timer
- ============
+Master-Timer
+============
+(w) by Matthias Schniedermeyer (ms@citd.de)
1. Einleitung
-------------
Master-Timer ist ein System zum automatischen Aufnehmen von Serien und Filmen.
+Beim Aufruf werden die Konfigurationsdateien gelesen, die Datei "epg.data" im
+aktuellen Verzeichnis nach passenden Sendungen durchsucht und die ermittelten
+Timer per SVDRP in VDR programmiert. Danach beendet sich Master-Timer.
-2. Voraussetzungen
-------------------
+Entsprechend empfiehlt es sich, Master-Timer per cronjob aufzurufen.
-VDR liefert die "epg.data".
-
-3. Konfigurationsdateien
+2. Konfigurationsdateien
------------------------
-Alle Konfigurationsdateien liegen unter "<HOME>.master-timer"
-
-config: Eine Ansammlung von Key-Value Paaren. Alle sind "optional" und
- erhalten dann die angegebenen Default-Werte
-
-(# = Kommentarzeilen)
-marginstart (Default 600)
- Anzahl der "Sicherheits" Sekunden die ein Timer frueher beginnen soll
-
-marginstop (Default 600)
- Anzahl der "Sicherheits" Sekunden die ein Timer laenger dauern soll
-
-defaultprio (Default 50)
- Die Prioritaet die fuer Timer verwendet wird wo keine Prioritaet
- angegeben ist
-
-DVBCards (Default 1)
- Anzahl der vorhandenen DVB-Karten (Derzeit nicht verwendet)
-
-Dest-Host (Default "localhost")
- Host-name oder IP des Rechners auf dem VDR laeuft
-
-Dest-Port (Default "2001")
- Port der VDR verwendet
-
-jointimers (Default 0)
- Sollen aufeinanderfolgende Timer auf den gleichen Kanal zusammengefasst
- werden (0 = "Nein", alles andere "Ja")
-
-debug (Default 0)
- Debug-Level, die einzelnen Debug-Werte muessen aus folgenden Werten
- zusammengezaehlt werden
- 1 : Dump "torecord"
- 2 : Dump all timers
- 4 : Show when a timer will be deleted
- 8 : Dump the "Done" REs
- 16 : Verbose Config-Reading
-
-deepblack: Eine Liste von Titeln die man NIEMALS NIMMER sehen will
- Jede Zeile = 1 Titel
-
-subtitle-movies: Eine Liste der "Subtitel" die ein Zeichen fuer einen Film sind
- (Soweit die von den Sendern richtig ausgefuellt sind.)
- Jede Zeile = 1 Subtitel
-
-torecord: Die Sachen die man Aufnehmen will
- Jede Zeile = 1 Timer
-# Format: (Every field is "optional".
-# [Title RE|Subtitle RE|Description RE|Channel-Name|Timeframe|Prio|Timer-Title]
-#
-# To record something at least one of the "Title", "Subtitle" or "Description"
-# Fields has to be provided. This 3 fields are "include" and the rest are
-# "exclude" fields!
-#
-# More than one channel definition can be provided. The delimiter is ";"
-# Additionaly you can make a "blacklist" of Channels when you prepent a "!" to the first Channel Definition
-# The "!" is only tested for the FIRST Channel definition.
-# You can only have a white or a blacklist (Mixing doesn't make sense!)
-#
-# ex. Record the series "Deep Space Nine" on Sci-Fantasy in the timeframe 09:00 - 14:00
-# Deep Space Nine|||Sci-Fantasy|0900-1400|99|DS9
-#
-# Record all "Actionfilm"s with "Schwarzenegger"
-# |Actionfilm|Schwarzenegger
-#
-
-
-done: The titles/subtitles which are already recorded/should not be recorded
- (Programmed Timers which got inserted into "done" will be deleted
- automaticaly)
-
-4. Notices
-----------
-
-- Recordings "overlapping" on the same channel, will be joined into one Timer
-- Title/Subtitle/Descriptions are "fixed" for Channel that don't fill them
- out "correctly" (Currently the "Bugs" from Pro-7/VOX/VIVA)
- Pro7: Remove the Title from the Subtitle '<Title> / <Subtitle>'
- VOX/VIVA: Subtitle is enclosed into "" and after ". " is the description
- VIVA: When the Subtitle beginns with space the subtitle is moved to
- description
- All (except the second VIVA one) fixes are tried onto ALL Subtitles.
-
-5. Known-Bugs
--------------
+Alle Konfigurationsdateien liegen unter "~/.master-timer". Es werden
+regulaere Ausdruecke ohne Unterscheidung der Gross-/Kleinschreibung
+benutzt.
+
+config: Die Hauptkonfigurationsdatei.
+
+deepblack: Eine Negativliste von Titeln, die man NIEMALS NIMMER sehen will.
+ Die epg-datensaetze werden beim Parsen einfach entfernt.
+
+subtitle-movies: Eine Liste der "Subtitel", die ein Zeichen fuer einen Film
+ sind (soweit die von den Sendern richtig ausgefuellt sind). Die
+ Einstellungen in dieser Datei werden fuer das Makro "MOVIE" in torecord
+ benutzt.
+ Kommentarzeilen sind nicht erlaubt.
+
+torecord: Liste der aufzunehmenden Filme.
+
+done: Liste der Titel/Subtitel, die bereits aufgenommen wurden. Timer, die
+ hier auftauchen, werden in VDR automatisch geloescht.
+
+channels-to-scan: Diese Kanaele werden vom Skript "scan-channels" durch-
+ geschaltet (zwecks Einlesen der EPG-Daten). Die Datei wird von Master-
+ Timer selbst nicht benutzt.
+
+3. Anmerkungen
+--------------
+
+- einige Sender fuellen die EPG-Felder nicht korrekt aus. Diese Fehler
+ werden von Master-Timer automatisch korrigiert.
+
+ Pro7: Title aus dem Subtitle entfernen '<Title> / <Subtitle>'
+ Pro7: Timer zwischen 00:00 und 05:00 werden einen Tag in die Zukunft
+ verschoben (Als unguten Nebeneffekt hat dies zur Folge das zum
+ aktuellen Tag NICHT die epg-Daten das folgenden Tags (=Das was in
+ der Fernsehzeitschrift noch auf der gleichen Seite ist) mehr gesendet
+ werden. Wenn man also "Last Minute" etwas aufnehmen will, dann muss
+ man (leider) einen Timer "per Hand" in VDR einprogrammieren!)
+ VOX/VIVA: Subtitle ist in "" eingeschlossen nd nach ". " steht die description
+ VIVA: Wenn der Subtitle mit einem Space beginnt, dann wird der komplette
+ Subtitle in die Description verschoben
+ RTL2: Wenn der EPG-Datensatz eine Dauer von kleiner/gleich 1 Sekunde hat,
+ wird er einfach verworfen.
+
+Bis auf den jeweils 2ten VIVA&Pro-7 Bug werden die Fixes an jedem
+epg-Datensatz ausprobiert.
+
+4. Bekannte Bugs
+----------------
-- It isn't checked if there are enough DVB-Cards
-- Overlapping Timers, on the same channel, are always joined
-- JOINed timers which are "done" don't get deleted automaticaly
+- Es wird nicht geprueft ob noch genug DVB-Karten vorhanden sind
+- "Joined timers" werden nur automatisch geloescht wenn alle dazugehoerigen
+ Sendungen "done" sind.
diff --git a/Tools/master-timer/README b/Tools/master-timer/README
index c71e6e1..05cc41a 100644
--- a/Tools/master-timer/README
+++ b/Tools/master-timer/README
@@ -1,43 +1,49 @@
- Master-Timer (w) by Matthias Schniedermeyer (ms@citd.de)
- ============
+Master-Timer
+============
+(w) by Matthias Schniedermeyer (ms@citd.de)
1. Introduction
---------------
-Master-Timer ist a system for recording Films/Series automaticaly
+Master-Timer is a system designed for automatically recording movies.
+Upon execution it reads its configuration files, scans the file "epg.data"
+in the current directory for matching titles and programs them via SVDRP
+into VDR.
-2. Requierements
-----------------
+You may for example run Master-Timer as a cron job.
-epg.data
-
-3. Config-Files
+2. Config files
---------------
-For all files: One Entry per Line. Each line is a "Regular Expresion"
- So you can use all Perl-Style REs you want.
- The RE are matched with "i" so they are case insensitive!
- (Except for the "done"-list, these must match excatly!)
+Configuration files are located in "~/.master-timer". Each entry is a
+regular expression so you can use all Perl style REs you want. They are
+processed case insensitive.
+
+config: Main configuration file.
-deepblack: Blacklist of "Titles" you NEVER EVER want to get to you eyes
+deepblack: Blacklist of "titles" you NEVER EVER want to see.
-subtitle-movies: A list of "Subtitles" which indicate a movie.
- (For Channels that correctly fill out the Subtitle.
- e.g. it won't work for *eRTL*)
+subtitle-movies: A list of "Subtitles" which indicate a movie (used
+ by the "MOVIE" macro in torecord).
+ For channels that correctly fill out the subtitle e.g. it will not
+ work with *eRTL*.
-torecord: The titles/subtitles/Description you want to record
+torecord: The titles you want to record.
done: The titles/subtitles which are already recorded/should not be recorded
- (Programmed Timers which got inserted into "done" will be deleted
- automaticaly)
+ Programmed timers which got inserted into "done" will be deleted
+ automatically.
+
+channels-to-scan: Used only by the separate "scan-channels" script which
+ switches through channels in order to get EPG data.
4. Notices
----------
-- Recordings "overlapping" on the same channel, will be joined into one Timer
-- Title/Subtitle/Descriptions are "fixed" for Channel that don't fill them
- out "correctly" (Currently the "Bugs" from Pro-7/VOX/VIVA)
+- Recordings overlapping on the same channel will be joined into one timer
+- Title/Subtitle/Descriptions are "fixed" for channels that don't fill them
+ out correctly (Pro-7/VOX/VIVA)
Pro7: Remove the Title from the Subtitle '<Title> / <Subtitle>'
VOX/VIVA: Subtitle is enclosed into "" and after ". " is the description
VIVA: When the Subtitle beginns with space the subtitle is moved to
@@ -48,5 +54,5 @@ done: The titles/subtitles which are already recorded/should not be recorded
-------------
- It isn't checked if there are enough DVB-Cards
-- Overlapping Timers, on the same channel, are always joined
-- JOINed timers which are "done" don't get deleted automaticaly
+- Overlapping timers on the same channel are always joined
+- Joined timers which are "done" don't get deleted automatically
diff --git a/Tools/master-timer/THANKS b/Tools/master-timer/THANKS
new file mode 100644
index 0000000..04bb13b
--- /dev/null
+++ b/Tools/master-timer/THANKS
@@ -0,0 +1,18 @@
+Klaus Schmidinger
+ - VDR
+
+Malte Kiesel
+ - Suggestions
+ - Bug Reports
+ - Documentation Updates for README/LIESMICH/torecord/deepblack/config
+
+Guido Fiala
+ - Suggestions
+ - Bug Repots
+ - finding bugs i found just before i read that part of his mails
+ (First the bug, then the errormessages! Otherwise i will search/find
+ the bug myself :-))) )
+
+Axel Gruber
+ - Suggestions
+ - Bug Reports
diff --git a/Tools/master-timer/Todo b/Tools/master-timer/Todo
index 722ee96..1757ade 100644
--- a/Tools/master-timer/Todo
+++ b/Tools/master-timer/Todo
@@ -1,9 +1,5 @@
-- "Intelligenter" Kanal-Scanner (z.B. nur 1 Kanal fuer ein
- Sender-"Gruppe")
-- Filtern nach Serie/Film
- "Komfortable" Anzeige, mit Black & Whitelisten, fuer Genres/Titeln usw.
-- Unterstueztung von 1xVDR pro Karte
- Abspielen (mit automatischen "killen" des "Frontend"-VDRs) von
Aufzeichnungen
- "View"-Timer d.h. Timer der nicht Aufnimmt sondern nur den Kanal aendert
diff --git a/Tools/master-timer/convert-DTV2VDR.pl b/Tools/master-timer/convert-DTV2VDR.pl
new file mode 100755
index 0000000..fb2a783
--- /dev/null
+++ b/Tools/master-timer/convert-DTV2VDR.pl
@@ -0,0 +1,151 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+# The EPG-Entrys
+my (%Entry, %channel, $mode);
+
+# 0 = VDR -> DTV
+# 1 = DTV -> VDR
+$mode = 0;
+
+read_channel_list();
+if ($mode) {
+ &read_dtv();
+ &read_epgdata();
+} else {
+ &read_epgdata();
+ &read_dtv();
+}
+&print_VDR();
+
+sub read_epgdata {
+ my ($channel, $duration, $title, $subtitle, $description, $time);
+ open (FI,"epg.data") or die ("Can't open file \"epg.data\"\n");
+
+ while (<FI>) {
+ # Begin Channel
+ if (/^C\s(\d+)\s+(.+)/) {
+ $channel=$2;
+ while (<FI>) {
+ # End Channel
+ if (/^c$/) {
+ last;
+ }
+ # Begin Timer
+ elsif (/^E\s(\d+)\s+(\d+)\s+(\d+)$/) {
+ # Undef this Variables because it is possibel that not every timer uses this values
+ undef $duration;
+ undef $subtitle;
+ undef $description;
+
+ $time=$2;
+ $duration=$3;
+ }
+ # Title
+ elsif (/^T\s(.*)/) {
+ $title=$1;
+ }
+ # Subtitle
+ elsif (/^S\s(.*)/) {
+ $subtitle=$1;
+ }
+ # Description
+ elsif (/^D\s(.*)/) {
+ $description=$1;
+ }
+ # End Timer
+ elsif (/^e$/) {
+ if ($mode) {
+ # DTV -> VDR
+ $Entry{$channel}{$time}{subtitle}=$subtitle if ($subtitle);
+ if ($description) {
+ if ($Entry{$channel}{$time}{description}) {
+ $Entry{$channel}{$time}{description} = "DTV: '$Entry{$channel}{$time}{description}' VDR: '$description'";
+ } else {
+ $Entry{$channel}{$time}{description} = "DTV: '' VDR: '$description'";
+ }
+ }
+ } else {
+ # VDR -> DTV
+ $Entry{$channel}{$time}{title}=$title;
+ $Entry{$channel}{$time}{duration}=$duration;
+ $Entry{$channel}{$time}{subtitle}=$subtitle if ($subtitle);
+ $Entry{$channel}{$time}{description}=$description if ($description);
+ }
+ }
+ }
+ }
+ }
+ close (FI);
+}
+
+sub read_dtv {
+ my ($channel, $time, $duration, $title, $category, $subtitle, $description);
+ open (FI,$ARGV[0]) or die "Can't open DTV-File";
+
+ while (<FI>) {
+ chomp;
+ ($channel, $time, $duration, $title, $category, $subtitle, $description) = split (/\|/);
+ if (!$channel{$channel}) {
+ next;
+ }
+ $channel = $channel{$channel};
+ if ($mode) {
+ # DTV -> VDR
+ if (!$subtitle && $description =~ /^\"(.*?)\"\:\s(.*)/) {
+ $Entry{$channel}{$time}{subtitle} = $1;
+ $description = $2;
+ }
+ $Entry{$channel}{$time}{title} = $title;
+ $Entry{$channel}{$time}{duration} = $duration;
+ $Entry{$channel}{$time}{subtitle} = $subtitle if ($subtitle);
+ $Entry{$channel}{$time}{category} = $category if ($category);
+ $Entry{$channel}{$time}{description} = $description if ($description);
+ } else {
+ # VDR -> DTV
+ $Entry{$channel}{$time}{category} = $category if ($category);
+ if ($description) {
+ if (!$Entry{$channel}{$time}{subtitle} && $description =~ /^\"(.*?)\"\:\s(.*)/) {
+ $Entry{$channel}{$time}{subtitle} = $1;
+ $description = $2;
+ }
+ if ($Entry{$channel}{$time}{description}) {
+ $Entry{$channel}{$time}{description} = "DTV: '$description' VDR: '$Entry{$channel}{$time}{description}'";
+ } else {
+ $Entry{$channel}{$time}{description} = "DTV: '$description' VDR: ''";
+ }
+ }
+ }
+ }
+ close (FI);
+}
+
+sub read_channel_list {
+ my ($old, $new);
+ open (FI,"$ENV{HOME}/.master-timer/convert-channel-list") or die ("Can't read channel-List");
+ while (<FI>) {
+ chomp;
+ ($old, $new) = split (/\|/);
+ $channel{$old} = $new;
+ }
+ close (FI);
+}
+
+sub print_VDR() {
+ my ($channel, $title, $time);
+ foreach $channel (sort keys %Entry) {
+ print "C 1 $channel\n";
+ foreach $time (sort keys %{%Entry->{$channel}}) {
+ if ($Entry{$channel}{$time}{duration}) {
+ print "E 1 $time $Entry{$channel}{$time}{duration}\n";
+ print "K $Entry{$channel}{$time}{category}\n" if ($Entry{$channel}{$time}{category});
+ print "T $Entry{$channel}{$time}{title}\n";
+ print "S $Entry{$channel}{$time}{subtitle}\n" if ($Entry{$channel}{$time}{subtitle});
+ print "D $Entry{$channel}{$time}{description}\n" if ($Entry{$channel}{$time}{description});
+ print "e\n";
+ }
+ }
+ print "c\n";
+ }
+}
diff --git a/Tools/master-timer/convert-oldtorecord.pl b/Tools/master-timer/convert-oldtorecord.pl
new file mode 100755
index 0000000..853c20b
--- /dev/null
+++ b/Tools/master-timer/convert-oldtorecord.pl
@@ -0,0 +1,61 @@
+#!/usr/bin/perl
+
+while (<>)
+ {
+ chomp;
+ if ($_ && !(/^\#/))
+ {
+ ($title, $subtitle, $description, $channel, $timeframe, $prio, $timer_title, $margin, $machine) = split (/\|/,$_);
+
+ if ($timer_title) {
+ print "[$timer_title]\n";
+ } elsif ($title) {
+ print "[$title]\n";
+ } elsif ($subtitle) {
+ print "[$subtitle]\n";
+ } elsif ($description) {
+ print "[$description]\n";
+ } else {
+ die ("Illegal Format");
+ }
+
+ # Accept torecord only if it is for the current machine
+ if ($title)
+ {
+ print "Title = $title\n";
+ }
+ if ($subtitle)
+ {
+ print "Subtitle = $subtitle\n";
+ }
+ if ($description)
+ {
+ print "Description = $description\n";
+ }
+ if ($channel)
+ {
+ print "Channel = $channel\n";
+ }
+ if ($timeframe)
+ {
+ print "Timeframe = $timeframe\n";
+ }
+ if ($prio)
+ {
+ print "Prio = $prio\n";
+ }
+ if ($timer_title)
+ {
+ print "Timertitle = $timer_title\n";
+ }
+ if ($margin)
+ {
+ print "Margin = $margin\n";
+ }
+ if ($machine)
+ {
+ print "Instance = $machine\n";
+ }
+ print "\n";
+ }
+ }
diff --git a/Tools/master-timer/master-timer.pl b/Tools/master-timer/master-timer.pl
index 3b98acc..5ddf909 100755
--- a/Tools/master-timer/master-timer.pl
+++ b/Tools/master-timer/master-timer.pl
@@ -5,6 +5,8 @@ use strict;
use Socket;
# For converting the Timers, read from VDR, back to Unix-Timestamps
use Time::Local;
+# For parsing the command line
+use Getopt::Std;
# Debugmode
# You have to add the following numbers to build the debug-var
@@ -13,7 +15,9 @@ use Time::Local;
# 4 : Show when a timer will be deleted
# 8 : Dump the "Done" REs
# 16 : Verbose Config-Reading
-my $debug = 0;
+# 32 : Dump Program Variable
+# 64 : Excessive deepblack/torecord debuging
+my $debug = 6;
# The Supervariable Program
# %Program{$title}{$channel}{$time}{duration}
@@ -23,26 +27,51 @@ my $debug = 0;
# The Supervariable Timer
# %Timer{$time}{$channel}{$title}{duration}
# {subtitle}
+# {description}
# {prio}
+# {lifetime}
# {real_title}
# {VDR} (Already programmed)
# The Value of VDR is ">0" for the position in the Timer-List or "R" for a "Repeating" Timer.
# A Value of >1.000.000 is a Master Timer-Timer which is already programmed into VDR
+# The Supervariable torecord/deepblack
+# $torecord{timercount}
+# {titleRE}
+# {subtitleRE}
+# {descriptionRE}
+# {title}[COUNT]
+# {subtitle}[COUNT]
+# {description}[COUNT]
+# {timeframe}[COUNT]
+# {blackchannel}[COUNT] or {channel}[COUNT]
+# {weekday}[COUNT]
+# {minlength}[COUNT]
+# {maxlength}[COUNT]
+# {prio}[COUNT]
+# {timertitle}[COUNT]
+# {marginstart}[COUNT]
+# {marginstop}[COUNT]
+# {instance}[COUNT]
+
# Variable-Definition
my (%Program, @channels, %channels, %Timer);
# Which Subtitles are Movies
my ($subtitle_movie);
+my ($test_subtitle_movie);
# Blacklist
-my ($title_deepblack);
+my (%deepblack);
# What is already recorded/Should not be recorded
my ($title_done, $subtitle_done);
# What to record
-my ($title_torecord, $subtitle_torecord, $description_torecord, @title_torecord, @subtitle_torecord, @description_torecord, @channel_torecord, @timeframe_torecord, @prio_torecord, @timer_title_torecord, $num_torecord, @marginstart_torecord, @marginstop_torecord, @machine_torecord);
+my (%torecord);
+
+# The Commandline
+my (%Opts);
# Default Priority for Timers (Config: defaultprio)
my $default_prio = 50;
@@ -63,1107 +92,1321 @@ my @Dest = ("localhost:2001"); # Config: Dest
# Which VDR-Instance shall be used
my $currentVDR = 1;
-# Working-Variables
-my ($title, $duration, $subtitle, $channel, $time, $description, $hit);
-my (@time, @date);
+# Where are the Config-Files
+my $configdir = "$ENV{HOME}/.master-timer";
-sub sub_die
- {
- my ($error) = @_;
- &closesocket();
- die "$error";
- }
+# Should the description be transfered to VDR?
+my $Description = 0;
+# Working-Variables
+my ($title, $duration, $subtitle, $channel, $time, $description, $category, $hit);
+my (@time, @date);
-if ($ARGV[0])
- {
- $currentVDR = $ARGV[0];
- }
+END {
+ &closesocket();
+}
&init();
&dumpdone() if ($debug & 8);
-&dumptorecord() if ($debug & 1);
+&dumptorecord("torecord") if ($debug & 1);
+&dumptorecord("deepblack") if ($debug & 1);
+print "Subtitle-Movie \"$subtitle_movie\"\n" if($debug & 1);
+# If we only have to dump the running series then exit after dumping them
+if ($Opts{s}) {
+ &dumpepgdata;
+ exit 0;
+}
+&processdone();
&fetchVDRTimers();
&process_torecord();
print "Timers before joining\n" if ($debug & 2 && $jointimers);
&dumptimers() if ($debug & 2);
-if ($jointimers)
- {
- &jointimers();
- print "Timers after joining\n" if ($debug & 2);
- &dumptimers() if ($debug & 2);
- }
+
+if ($jointimers) {
+ &jointimers();
+ print "Timers after joining\n" if ($debug & 2);
+ &dumptimers() if ($debug & 2);
+}
+
+&dumpepgdata if ($debug & 32);
&printtimers();
&transfertimers();
-&closesocket();
+
+#
+# End of Program
+#
#
# Subfunctions
#
-sub dumpdone()
- {
- print "Start Done-dump\n";
- print "Titledone: \"$title_done\"\n";
- print "Subtitledone \"$subtitle_done\"\n";
- print "End Done-dump\n";
+sub dumpdone() {
+ print "Start Done-dump\n";
+ print "Titledone: \"$title_done\"\n";
+ print "Subtitledone \"$subtitle_done\"\n";
+ print "End Done-dump\n";
+}
+
+sub dumpepgdata () {
+ print "Start EPG-Dump\n";
+ foreach $title (sort keys %Program) {
+ foreach $channel (sort keys %{%Program->{$title}}) {
+ foreach $time (sort {$a <=> $b} keys %{%Program->{$title}->{$channel}}) {
+ print "Title: \"$title\" ";
+ if (!$Opts{s}) {
+ print "Subtitle: \"$Program{$title}{$channel}{$time}{subtitle}\" " if ($Program{$title}{$channel}{$time}{subtitle});
+ print "Time: \"$time\"";
+ }
+ print "Channel: \"$channel\"";
+ print "\n";
+ if ($Opts{s}) {
+ last;
+ }
+ }
+ }
+ }
+ print "End EPG-Dump\n";
+}
+
+
+sub dumptorecord() {
+ my ($context) = shift;
+ my ($rContext);
+
+ if ($context eq "torecord") {
+ $rContext = \%torecord;
+ } elsif ($context eq "deepblack") {
+ $rContext = \%deepblack;
+ } else {
+ die ("Illegal Context");
}
-sub dumptorecord()
- {
- print "Start Torecord-dump\n";
- print "Regex-Title: $title_torecord\n";
- print "Regex-Subtitle: $subtitle_torecord\n";
- print "Regex-Description: $description_torecord\n";
- foreach my $num (0 .. $num_torecord)
- {
- print "Timer Number $num: ";
-
- print "Title: \"$title_torecord[$num]\" " if ($title_torecord[$num]);
- print "Title: \"\" " unless ($title_torecord[$num]);
-
- print "Subtitle: \"$subtitle_torecord[$num]\" "if ($subtitle_torecord[$num]);
- print "Subtitle: \"\" " unless ($subtitle_torecord[$num]);
+ print "Start $context-dump\n";
+ print "Regex-Title: $$rContext{titleRE}\n";
+ print "Regex-Subtitle: $$rContext{subtitleRE}\n";
+ print "Regex-Description: $$rContext{descriptionRE}\n";
+ foreach my $num (0 .. $$rContext{timercount}) {
+ print "Entry Number $num: ";
+
+ print "Title: \"$$rContext{title}[$num]\" " if ($$rContext{title}[$num]);
+ print "Title: \"\" " unless ($$rContext{title}[$num]);
+
+ print "Subtitle: \"$$rContext{subtitle}[$num]\" "if ($$rContext{subtitle}[$num]);
+ print "Subtitle: \"\" " unless ($$rContext{subtitle}[$num]);
+
+ print "Description: \"$$rContext{description}[$num]\" " if ($$rContext{description}[$num]);
+ print "Description: \"\" " unless ($$rContext{description}[$num]);
+
+ print "Category: \"$$rContext{category}[$num]\" " if ($$rContext{category}[$num]);
+ print "Category: \"\" " unless ($$rContext{category}[$num]);
- print "Description: \"$description_torecord[$num]\" " if ($description_torecord[$num]);
- print "Description: \"\" " unless ($description_torecord[$num]);
+ print "Timeframe: \"$$rContext{timeframe}[$num]\" " if ($$rContext{timeframe}[$num]);
+ print "Timeframe: \"\" " unless ($$rContext{timeframe}[$num]);
- print "Timeframe: \"$timeframe_torecord[$num]\" " if ($timeframe_torecord[$num]);
- print "Timeframe: \"\" " unless ($timeframe_torecord[$num]);
+ print "Weekday: \"$$rContext{weekday}[$num]\" " if ($$rContext{weekday}[$num]);
+ print "Weekday: \"\" " unless ($$rContext{weekday}[$num]);
- print "Channel: \"". join (";",@{$channel_torecord[$num]})."\" " if ($channel_torecord[$num]);
- print "Channel: \"\" " unless ($channel_torecord[$num]);
+ print "Channel: \"$$rContext{channel}[$num]\" " if ($$rContext{channel}[$num]);
+ print "Channel: \"\" " unless ($$rContext{channel}[$num]);
- print "Prio: \"$prio_torecord[$num]\" " if ($prio_torecord[$num]);
- print "Prio: \"\" " unless ($prio_torecord[$num]);
+ print "Blackchannel: \"$$rContext{blackchannel}[$num]\" " if ($$rContext{blackchannel}[$num]);
+ print "Blackchannel: \"\" " unless ($$rContext{blackchannel}[$num]);
- print "Timertitle: \"$timer_title_torecord[$num]\" " if ($timer_title_torecord[$num]);
- print "Timertitle: \"\" " unless ($timer_title_torecord[$num]);
+ print "Prio: \"$$rContext{prio}[$num]\" " if ($$rContext{prio}[$num]);
+ print "Prio: \"\" " unless ($$rContext{prio}[$num]);
+
+ print "Timertitle: \"$$rContext{timertitle}[$num]\" " if ($$rContext{timertitle}[$num]);
+ print "Timertitle: \"\" " unless ($$rContext{timertitle}[$num]);
- print "Marginstart: \"$marginstart_torecord[$num]\" " if ($marginstart_torecord[$num]);
- print "Marginstart: \"\" " unless ($marginstart_torecord[$num]);
+ print "Marginstart: \"$$rContext{marginstart}[$num]\" " if ($$rContext{marginstart}[$num]);
+ print "Marginstart: \"\" " unless ($$rContext{marginstart}[$num]);
- print "Marginstop: \"$marginstop_torecord[$num]\" " if ($marginstop_torecord[$num]);
- print "Marginstop: \"\" " unless ($marginstop_torecord[$num]);
+ print "Marginstop: \"$$rContext{marginstop}[$num]\" " if ($$rContext{marginstop}[$num]);
+ print "Marginstop: \"\" " unless ($$rContext{marginstop}[$num]);
- print "Machine: \"$machine_torecord[$num]\" " if ($machine_torecord[$num]);
- print "Machine: \"\" " unless ($machine_torecord[$num]);
+ print "Minlength: \"$$rContext{minlength}[$num]\" " if ($$rContext{minlength}[$num]);
+ print "Minlength: \"\" " unless ($$rContext{minlength}[$num]);
- print "\n";
- }
- print "End Torecord-dump\n";
+ print "Maxlength: \"$$rContext{maxlength}[$num]\" " if ($$rContext{maxlength}[$num]);
+ print "Maxlength: \"\" " unless ($$rContext{maxlength}[$num]);
+
+ print "Instance: \"$$rContext{instance}[$num]\" " if ($$rContext{instance}[$num]);
+ print "Instance: \"\" " unless ($$rContext{instance}[$num]);
+
+ print "\n";
}
+ print "End $context-dump\n";
+}
-sub dumptimers()
- {
- print "Start Timers-dump\n";
- foreach $time (sort {$a <=> $b} keys %Timer)
- {
- foreach $channel (sort keys %{%Timer->{$time}})
- {
- foreach $title (sort keys %{%Timer->{$time}->{$channel}})
- {
- my ($prio, @time, @date, @time2);
- my ($realtitle);
- @time = &GetTime ($time);
- @date = &GetDay ($time);
- @time2 = &GetTime ($time + $Timer{$time}{$channel}{$title}{duration});
- $subtitle = $Timer{$time}{$channel}{$title}{subtitle};
- $prio = $Timer{$time}{$channel}{$title}{prio};
- $realtitle = $Timer{$time}{$channel}{$title}{real_title};
- print "2:$channels{$channel}{number}:$date[1]:$time[0]$time[1]:$time2[0]$time2[1]:$prio:99:$title:Title: \"$realtitle\"||Subtitle: \"$subtitle\":$Timer{$time}{$channel}{$title}{VDR}\n";
- }
- }
+sub dumptimers() {
+ print "Start Timers-dump\n";
+ foreach $time (sort {$a <=> $b} keys %Timer) {
+ foreach $channel (sort keys %{%Timer->{$time}}) {
+ foreach $title (sort keys %{%Timer->{$time}->{$channel}}) {
+ my ($prio, $lifetime, @time, @date, @time2);
+ my ($realtitle);
+ @time = &GetTime ($time);
+ @date = &GetDay ($time);
+ @time2 = &GetTime ($time + $Timer{$time}{$channel}{$title}{duration});
+ $subtitle = $Timer{$time}{$channel}{$title}{subtitle};
+ $prio = $Timer{$time}{$channel}{$title}{prio};
+ $lifetime = $Timer{$time}{$channel}{$title}{lifetime};
+ $realtitle = $Timer{$time}{$channel}{$title}{real_title};
+ print "2:$channels{$channel}{number}:$date[1]:$time[0]$time[1]:$time2[0]$time2[1]:$prio:$lifetime:$title:Title: \"$realtitle\"||Subtitle: \"$subtitle\":$Timer{$time}{$channel}{$title}{VDR}\n";
}
- print "End Timers-dump\n";
+ }
}
+ print "End Timers-dump\n";
+}
-sub printtimers()
- {
- foreach $time (sort {$a <=> $b} keys %Timer)
- {
- foreach $channel (sort keys %{%Timer->{$time}})
- {
- foreach $title (sort keys %{%Timer->{$time}->{$channel}})
- {
- my ($prio, @time, @date, @time2);
- if ($Timer{$time}{$channel}{$title}{VDR} eq 0)
- {
- my ($realtitle);
- @time = &GetTime ($time);
- @date = &GetDay ($time);
- @time2 = &GetTime ($time + $Timer{$time}{$channel}{$title}{duration});
- $subtitle = $Timer{$time}{$channel}{$title}{subtitle};
- $prio = $Timer{$time}{$channel}{$title}{prio};
- $realtitle = $Timer{$time}{$channel}{$title}{real_title};
-
- print "2:$channels{$channel}{number}:$date[1]:$time[0]$time[1]:$time2[0]$time2[1]:$prio:99:$title:Title: \"$realtitle\"||Subtitle: \"$subtitle\"\n";
- }
- }
- }
+sub printtimers() {
+ foreach $time (sort {$a <=> $b} keys %Timer) {
+ foreach $channel (sort keys %{%Timer->{$time}}) {
+ foreach $title (sort keys %{%Timer->{$time}->{$channel}}) {
+ my ($prio, $lifetime, @time, @date, @time2);
+ if ($Timer{$time}{$channel}{$title}{VDR} eq 0) {
+ my ($realtitle);
+ @time = &GetTime ($time);
+ @date = &GetDay ($time);
+ @time2 = &GetTime ($time + $Timer{$time}{$channel}{$title}{duration});
+ $subtitle = $Timer{$time}{$channel}{$title}{subtitle};
+ $prio = $Timer{$time}{$channel}{$title}{prio};
+ $lifetime = $Timer{$time}{$channel}{$title}{lifetime};
+ $realtitle = $Timer{$time}{$channel}{$title}{real_title};
+
+ print "2:$channels{$channel}{number}:$date[1]:$time[0]$time[1]:$time2[0]$time2[1]:$prio:$lifetime:$title:Title: \"$realtitle\"||Subtitle: \"$subtitle\"\n";
+ }
}
+ }
}
+}
-sub transfertimers()
- {
- foreach $time (sort {$a <=> $b} keys %Timer)
- {
- foreach $channel (sort keys %{%Timer->{$time}})
- {
- foreach $title (sort keys %{%Timer->{$time}->{$channel}})
- {
- my ($prio, @time, @date, @time2, $realtitle, $result);
- if ($Timer{$time}{$channel}{$title}{VDR} eq 0)
- {
- @time = &GetTime ($time);
- @date = &GetDay ($time);
- @time2 = &GetTime ($time + $Timer{$time}{$channel}{$title}{duration});
- $subtitle = $Timer{$time}{$channel}{$title}{subtitle};
- $prio = $Timer{$time}{$channel}{$title}{prio};
- $realtitle = $Timer{$time}{$channel}{$title}{real_title};
-
- ($result) = GetSend ("newt 2:$channels{$channel}{number}:$date[1]:$time[0]$time[1]:$time2[0]$time2[1]:$prio:99:$title:Title: \"$realtitle\"||Subtitle: \"$subtitle\"");
- print "Timer: $result" if ($debug & 2);
- }
- }
+sub transfertimers() {
+ foreach $time (sort {$a <=> $b} keys %Timer) {
+ foreach $channel (sort keys %{%Timer->{$time}}) {
+ foreach $title (sort keys %{%Timer->{$time}->{$channel}}) {
+ my ($prio, $lifetime, $description, @time, @date, @time2, $realtitle, $result);
+ if ($Timer{$time}{$channel}{$title}{VDR} eq 0) {
+ @time = &GetTime ($time);
+ @date = &GetDay ($time);
+ @time2 = &GetTime ($time + $Timer{$time}{$channel}{$title}{duration});
+ $subtitle = $Timer{$time}{$channel}{$title}{subtitle};
+ $prio = $Timer{$time}{$channel}{$title}{prio};
+ $lifetime = $Timer{$time}{$channel}{$title}{lifetime};
+ if ($Description) {
+ $description = "||Description :\"$Timer{$time}{$channel}{$title}{description}\"";
+ } else {
+ $description = "";
}
+ $realtitle = $Timer{$time}{$channel}{$title}{real_title};
+
+ ($result) = GetSend ("newt 2:$channels{$channel}{number}:$date[1]:$time[0]$time[1]:$time2[0]$time2[1]:$prio:$lifetime:$title:Title: \"$realtitle\"||Subtitle: \"$subtitle\"$description");
+ print "Timer: $result" if ($debug & 2);
+ }
}
+ }
}
+}
# Convert the Unix-Time-Stamp into "month" and "Day of month"
-sub GetDay
- {
- my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(shift);
- $mon++;
- $mon = sprintf ("%02i",$mon);
- $mday = sprintf ("%02i",$mday);
- return ($mon, $mday);
- }
+sub GetDay {
+ my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(shift);
+ $mon++;
+ $mon = sprintf ("%02i",$mon);
+ $mday = sprintf ("%02i",$mday);
+ return ($mon, $mday);
+}
+# Convert the Unix-Time-Stramp into Weekday
+sub GetWDay {
+ my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(shift);
+ return ($wday);
+}
# Convert the Unix-Time-Stramp into "hour" and "minute"
-sub GetTime
- {
- my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(shift);
- $hour = sprintf ("%02i",$hour);
- $min = sprintf ("%02i",$min);
- return ($hour, $min);
- }
+sub GetTime {
+ my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(shift);
+ $hour = sprintf ("%02i",$hour);
+ $min = sprintf ("%02i",$min);
+ return ($hour, $min);
+}
# Workaround some EPG-Bugs
-sub correct_epg_data
- {
- if ($subtitle)
- {
- # For Pro-7. Remove $title from $subtitle
- $subtitle =~ s/$title\s\/\s//;
+sub correct_epg_data {
+ if ($subtitle) {
+ # For Pro-7. Remove $title from $subtitle
+ $subtitle =~ s/\Q$title\E\s\/\s//;
- # For VOX & VIVA. The Format it '"<Subtitle>". <Description>'
- if ($subtitle =~ /^\"(.*?)\"\.\s(.*)/)
- {
- # Lets see if there are Channels that where the VOX/VIVA scheme matches, but also have a description
- if ($description)
- {
- sub_die ("Subtitle: \"$subtitle\"\nDescription\"$description\"\n");
- }
- $subtitle = $1;
- $description = $2;
- }
- elsif ($channel eq "VIVA")
- {
- if ($subtitle =~ /^\s(.*)/)
- {
- $subtitle = "";
- $description = $1;
- }
- }
+ # For VOX & VIVA. The Format it '"<Subtitle>". <Description>'
+ if ($subtitle =~ /^\"(.*?)\"\.\s(.*)/) {
+ # Lets see if there are Channels that where the VOX/VIVA scheme matches, but also have a description
+ if ($description) {
+ my $one = $1;
+ my $two = $2;
+ if ($description =~ /^DTV\:\s\'(.*)\' VDR:\s\'\'$/) {
+ $description = "DTV: '$1' VDR: '$two'";
+ $subtitle = $one;
+ } else {
+ die ("Title: \"$title\" Channel: \"$channel\" Subtitle: \"$subtitle\"\nDescription: \"$description\"\n");
+ }
}
-
- # Workaround for the broken PRO-7/Kabel-1 EPG-Date. If Time is between 00.00 and 05.00 the time is shifted forward by a day
- if ($channel eq "Pro-7" || $channel eq "Kabel-1")
- {
- my (@time);
- @time = GetTime ($time);
- if ($time[0] >= 0 && ($time[0] <= 4 || ($time[0] == 5 && $time[1] == 0)))
- {
- $time += 24*60*60;
- }
+ $subtitle = $1;
+ $description = $2;
+ }
+ elsif ($channel eq "VIVA") {
+ if ($subtitle =~ /^\s(.*)/) {
+ $subtitle = "";
+ $description = $1;
}
+ }
+ }
+
+ # Workaround for the broken PRO-7/Kabel-1 EPG-Date. If Time is between 00.00 and 05.00 the time is shifted forward by a day
+ if ($channel eq "Pro-7" || $channel eq "Kabel-1") {
+ my (@time);
+ @time = GetTime ($time);
+ if ($time[0] >= 0 && ($time[0] <= 4 || ($time[0] == 5 && $time[1] == 0))) {
+ $time += 24*60*60;
+ }
+ }
}
# Add a Recording into the "to record"-List
-sub addtimer
- {
- my ($hit, $title, $realtitle, $subtitle, $channel, $time, $duration, $prio, $VDR, $time2, $title2, $channel2, $marginstart, $marginstop);
- ($title, $realtitle, $subtitle, $channel, $time, $duration, $prio, $VDR, $marginstart, $marginstop) = @_;
-# print "Title: \"$title\" Realtitle: \"$realtitle\" Subtitle: \"$subtitle\" Channel: \"$channel\" Time: \"$time\" Duration: \"$duration\" Prio: \"$prio\" VDR: \"$VDR\"\n";
-
- $hit = 1;
-
- foreach $time2 (sort keys %Timer)
- {
- foreach $title2 (sort keys %{%Timer->{$time2}->{$channel}})
- {
- my ($ctime, $ctime2);
- $ctime = $time2;
- $ctime2 = $time2 + $Timer{$time2}{$channel}{$title2}{duration};
-
- if (($time >= $ctime) && ($time <= $ctime2))
- {
- undef $hit;
- }
- }
+sub addtimer {
+ my ($title, $realtitle, $subtitle, $channel, $time, $duration, $prio, $lifetime, $description, $VDR, $time2, $title2, $channel2, $marginstart, $marginstop);
+ ($title, $realtitle, $subtitle, $description, $channel, $time, $duration, $prio, $lifetime, $VDR, $marginstart, $marginstop) = @_;
+# print "Title: \"$title\" Realtitle: \"$realtitle\" Subtitle: \"$subtitle\" Channel: \"$channel\" Time: \"$time\" Duration: \"$duration\" Prio: \"$prio\" VDR: \"$VDR\"\n";
+
+ foreach $time2 (sort keys %Timer) {
+ foreach $title2 (sort keys %{%Timer->{$time2}->{$channel}}) {
+ my ($ctime, $ctime2);
+ $ctime = $time2;
+ $ctime2 = $time2 + $Timer{$time2}{$channel}{$title2}{duration};
+
+ if (($time >= $ctime) && ($time <= $ctime2)) {
+ return;
}
+ }
+ }
+ $time -= $marginstart;
+ $duration += $marginstart + $marginstop;
+ $Timer{$time}{$channel}{$title}{duration}=$duration;
+ $Timer{$time}{$channel}{$title}{subtitle}=$subtitle;
+ $Timer{$time}{$channel}{$title}{description}=$description;
+ $Timer{$time}{$channel}{$title}{prio}=$prio;
+ $Timer{$time}{$channel}{$title}{lifetime}=$lifetime;
+ $Timer{$time}{$channel}{$title}{VDR}=$VDR;
+ $Timer{$time}{$channel}{$title}{real_title}=$realtitle;
+}
- if ($hit)
- {
- $time -= $marginstart;
- $duration += $marginstart + $marginstop;
- $Timer{$time}{$channel}{$title}{duration}=$duration;
- $Timer{$time}{$channel}{$title}{subtitle}=$subtitle;
- $Timer{$time}{$channel}{$title}{prio}=$prio;
- $Timer{$time}{$channel}{$title}{VDR}=$VDR;
- $Timer{$time}{$channel}{$title}{real_title}=$realtitle;
- }
- }
+sub deltimer() {
+ my ($time, $channel, $title, $delete_from_VDR);
+ ($time, $channel, $title, $delete_from_VDR) = @_;
-sub deltimer()
- {
- my ($time, $channel, $title, $delete_from_VDR);
- ($time, $channel, $title, $delete_from_VDR) = @_;
-
-# if ($delete_from_VDR)
-# {
-# if ($Timer{$time}{$channel}{$title}{VDR})
-# {
-# if ($Timer{$time}{$channel}{$title}{VDR} =~ s/ ^R/)
-# {
-# print "Error: A Repeating-Timer can't be deleted from VDR: \"$title\"\n";
-# }
-# elsif ($Timer{$time}{$channel}{$title}{VDR} < 1000000)
-# {
-# print "A User-Programmed Timer has been deleted from VDR: \"$title\"\n";
-# }
-# else
-# {
-#
-# }
-# }
+# if ($delete_from_VDR) {
+# if ($Timer{$time}{$channel}{$title}{VDR}) {
+# if ($Timer{$time}{$channel}{$title}{VDR} =~ s/ ^R/) {
+# print "Error: A Repeating-Timer can't be deleted from VDR: \"$title\"\n";
+# }
+# elsif ($Timer{$time}{$channel}{$title}{VDR} < 1000000) {
+# print "A User-Programmed Timer has been deleted from VDR: \"$title\"\n";
+# }
+# else {
+#
# }
+# }
+# }
+
+ delete $Timer{$time}{$channel}{$title}{duration};
+ delete $Timer{$time}{$channel}{$title}{subtitle};
+ delete $Timer{$time}{$channel}{$title}{prio};
+ delete $Timer{$time}{$channel}{$title}{VDR};
+ delete $Timer{$time}{$channel}{$title}{real_title};
+ delete $Timer{$time}{$channel}{$title};
+ delete $Timer{$time}{$channel} if (keys %{ $Timer{$time}{$channel} } == 1);
+ delete $Timer{$time} if (keys %{ $Timer{$time} } == 1);
+}
- delete $Timer{$time}{$channel}{$title}{duration};
- delete $Timer{$time}{$channel}{$title}{subtitle};
- delete $Timer{$time}{$channel}{$title}{prio};
- delete $Timer{$time}{$channel}{$title}{VDR};
- delete $Timer{$time}{$channel}{$title}{real_title};
- delete $Timer{$time}{$channel}{$title};
- delete $Timer{$time}{$channel} if (keys %{ $Timer{$time}{$channel} } == 1);
- delete $Timer{$time} if (keys %{ $Timer{$time} } == 1);
- }
+sub delprogram() {
+ my ($title, $channel, $time);
+ ($title, $channel, $time) = @_;
-sub jointimers
- {
- #
- # FIXME: 2 Timers on the same channel will always be joined.
- # It should be checked if there is another DVB-Card available.
- #
- # FIXME2: When one timer is already programmed in VDR, delete that timer in VDR.
- my ($running, $counter, @times, $channel, $title, $channel2, $title2);
- $running = 1;
- outer: while ($running)
- {
- $counter = 0;
- @times = sort {$a <=> $b} keys %Timer;
-
- # We only need to check till the second last timer. The last one can't have a overlapping one.
- while ($counter < $#times)
- {
- foreach $channel (sort keys %{%Timer->{$times[$counter]}})
- {
- foreach $title (sort keys %{%Timer->{$times[$counter]}->{$channel}})
- {
- if ($times[$counter + 1] < ($times[$counter] + $Timer{$times[$counter]}{$channel}{$title}{duration}))
- {
- foreach $channel2 (sort keys %{%Timer->{$times[$counter + 1]}})
- {
- foreach $title2 (sort keys %{%Timer->{$times[$counter + 1]}->{$channel}})
- {
- if ($channel eq $channel2)
- {
- my ($duration, $subtitle, $prio, $realtitle, $duration2, $subtitle2, $prio2, $realtitle2);
- # Values from Lower-Timer
- $duration = $Timer{$times[$counter]}{$channel}{$title}{duration};
- $subtitle = $Timer{$times[$counter]}{$channel}{$title}{subtitle};
- $prio = $Timer{$times[$counter]}{$channel}{$title}{prio};
- $realtitle = $Timer{$times[$counter]}{$channel}{$title}{real_title};
-
- # Values from Higher-Timer
- $duration2 = $Timer{$times[$counter + 1]}{$channel2}{$title2}{duration};
- $subtitle2 = $Timer{$times[$counter + 1]}{$channel2}{$title2}{subtitle};
- $prio2 = $Timer{$times[$counter + 1]}{$channel2}{$title2}{prio};
- $realtitle2 = $Timer{$times[$counter + 1]}{$channel2}{$title2}{real_title};
-
- # Use the Higher Priority for the new Timer
- $prio = ($prio > $prio2) ? $prio : $prio2;
-
- # Delete the two "Obsolet" Timers
- &deltimer ($times[$counter], $channel, $title);
- &deltimer ($times[$counter + 1], $channel2, $title2);
-
- # And set the new one
- &addtimer ("$title + $title2", "$realtitle\~$realtitle2", "$subtitle\~$subtitle2", $channel, $times[$counter], $duration2 + ($times[$counter + 1 ] - $times[$counter]),$prio,0,0,0);
-
- # Now a Value is "missing", so we will redo the whole thing. (This will do three-times JOIN correct)
- redo outer;
- }
- }
- }
- }
- }
+ delete $Program{$title}{$channel}{$time};
+ delete $Program{$title}{$channel} if (keys %{ $Program{$title}{$channel} } == 1);
+ delete $Program{$title} if (keys %{ $Program{$title} } == 1);
+}
+
+sub jointimers {
+ #
+ # FIXME: 2 Timers on the same channel will always be joined.
+ # It should be checked if there is another DVB-Card available.
+ #
+ # FIXME2: When one timer is already programmed in VDR, delete that timer in VDR.
+ my ($running, $counter, @times, $channel, $title, $channel2, $title2);
+ $running = 1;
+ outer: while ($running) {
+ $counter = 0;
+ @times = sort {$a <=> $b} keys %Timer;
+
+ # We only need to check till the second last timer. The last one can't have a overlapping one.
+ while ($counter < $#times) {
+ foreach $channel (sort keys %{%Timer->{$times[$counter]}}) {
+ foreach $title (sort keys %{%Timer->{$times[$counter]}->{$channel}}) {
+ if ($times[$counter + 1] < ($times[$counter] + $Timer{$times[$counter]}{$channel}{$title}{duration})) {
+ foreach $channel2 (sort keys %{%Timer->{$times[$counter + 1]}}) {
+ foreach $title2 (sort keys %{%Timer->{$times[$counter + 1]}->{$channel}}) {
+ if ($channel eq $channel2) {
+ my ($duration, $subtitle, $description, $prio, $lifetime, $realtitle, $duration2, $subtitle2, $description2, $prio2, $lifetime2, $realtitle2);
+ # Values from Lower-Timer
+ $duration = $Timer{$times[$counter]}{$channel}{$title}{duration};
+ $subtitle = $Timer{$times[$counter]}{$channel}{$title}{subtitle};
+ $description = $Timer{$times[$counter]}{$channel}{$title}{description};
+ $prio = $Timer{$times[$counter]}{$channel}{$title}{prio};
+ $lifetime = $Timer{$times[$counter]}{$channel}{$title}{lifetime};
+ $realtitle = $Timer{$times[$counter]}{$channel}{$title}{real_title};
+
+ # Values from Higher-Timer
+ $duration2 = $Timer{$times[$counter + 1]}{$channel2}{$title2}{duration};
+ $subtitle2 = $Timer{$times[$counter + 1]}{$channel2}{$title2}{subtitle};
+ $description2 = $Timer{$times[$counter + 1]}{$channel2}{$title2}{description};
+ $prio2 = $Timer{$times[$counter + 1]}{$channel2}{$title2}{prio};
+ $lifetime2 = $Timer{$times[$counter + 1]}{$channel2}{$title2}{lifetime};
+ $realtitle2 = $Timer{$times[$counter + 1]}{$channel2}{$title2}{real_title};
+
+ # Use the Higher Priority/Lifetime for the new Timer
+ $prio = ($prio > $prio2) ? $prio : $prio2;
+ $lifetime = ($lifetime > $lifetime2) ? $lifetime : $lifetime2;
+
+ # Delete the two "Obsolet" Timers
+ &deltimer ($times[$counter], $channel, $title);
+ &deltimer ($times[$counter + 1], $channel2, $title2);
+
+ # And set the new one
+ &addtimer ("$title + $title2", "$realtitle\~$realtitle2", "$subtitle\~$subtitle2", "$description\~$description2", $channel, $times[$counter], $duration2 + ($times[$counter + 1 ] - $times[$counter]),$prio,$lifetime,0,0,0);
+
+ # Now a Value is "missing", so we will redo the whole thing. (This will do three-times JOIN correct)
+ redo outer;
+ }
}
- $counter++;
+ }
}
- undef $running;
+ }
}
+ $counter++;
+ }
+ undef $running;
}
+}
-sub process_torecord
- {
- my ($first_hit, $prio, $timer_title);
- foreach $title (sort keys %Program)
- {
- foreach $channel (sort keys %{%Program->{$title}})
- {
- foreach $time (sort {$a <=> $b} keys %{%Program->{$title}->{$channel}})
- {
- undef $hit;
-
- # First look if any of the Title/Subtitle/Description REs match
- if ($title =~ /$title_torecord/i)
- {
- $hit = 1;
- }
- elsif ($Program{$title}{$channel}{$time}{subtitle} && $Program{$title}{$channel}{$time}{subtitle} =~ /$subtitle_torecord/i)
- {
- $hit = 1;
- }
- elsif ($Program{$title}{$channel}{$time}{description} && $Program{$title}{$channel}{$time}{description} =~ /$description_torecord/i)
- {
- $hit = 1;
- }
-
- # Now look if we have a "exact" hit
- if ($hit)
- {
- my ($counter);
- undef $hit;
- foreach $counter (0 .. $num_torecord)
- {
-
- if ($title_torecord[$counter])
- {
- if (!($title =~ /$title_torecord[$counter]/i))
- {
- next;
- }
- }
-
- if ($subtitle_torecord[$counter])
- {
- if (!($Program{$title}{$channel}{$time}{subtitle} =~ /$subtitle_torecord[$counter]/i))
- {
- next;
- }
- elsif (!$title_torecord[$counter] && !$description_torecord[$counter])
- {
- next;
- }
- }
-
- if ($description_torecord[$counter])
- {
- if ($Program{$title}{$channel}{$time}{description})
- {
- if (!($Program{$title}{$channel}{$time}{description} =~ /$description_torecord[$counter]/i))
- {
- next;
- }
- }
- elsif (!$title_torecord[$counter] && !$subtitle_torecord[$counter])
- {
- next;
- }
- }
-
- if ($channel_torecord[$counter])
- {
- my ($hit);
- # Blacklist-Mode
- if ($channel_torecord[$counter][0] =~ /^!/)
- {
- $hit = 1;
- foreach (0 .. $#{$channel_torecord[$counter]})
- {
- # Strip a possibel "!" Charactar
- $channel_torecord[$counter][$_] =~ /^!?(.*)/;
- if ($channel =~ /^$1$/)
- {
- undef $hit;
- last;
- }
- }
- }
- # Whitelist-Mode
- else
- {
- undef $hit;
- foreach (0 .. $#{$channel_torecord[$counter]})
- {
- # Strip a possibel "!" Charactar
- $channel_torecord[$counter][$_] =~ /^!?(.*)/;
- if ($channel =~ /^$1$/)
- {
- $hit = 1;
- last ;
- }
- }
- }
- if (!$hit)
- {
- next;
- }
- }
-
- if ($timeframe_torecord[$counter])
- {
- my (@time, $time2, $ctime, $ctime2);
- @time = GetTime($time);
- $time2 = "$time[0]$time[1]";
-
- ($ctime, $ctime2) = split (/\-/,$timeframe_torecord[$counter]);
-
- if (!$ctime)
- {
- $ctime = "0";
- }
- if (!$ctime2)
- {
- $ctime2 = "2400";
- }
-
- if ($ctime < $ctime2)
- {
- if (!($time2 >= $ctime && $time2 <= $ctime2))
- {
- next;
- }
- }
- else
- {
- if (!(($time2 >= $ctime && $time2 <= "2400") || ($time2 >= "0" && $time2 <= $ctime2)))
- {
- next;
- }
- }
- }
-
- if ($prio_torecord[$counter])
- {
- $prio = $prio_torecord[$counter];
- }
- else
- {
- $prio = 50;
- }
-
- # What Title to use for the timer
- if ($timer_title_torecord[$counter])
- {
- $timer_title = $timer_title_torecord[$counter]
- }
- elsif ($title_torecord[$counter])
- {
- $timer_title = $title_torecord[$counter]
- }
- else
- {
- $timer_title = $title;
- }
-
- my ($subtitle);
- if ($Program{$title}{$channel}{$time}{subtitle})
- {
- $subtitle = $Program{$title}{$channel}{$time}{subtitle};
- }
- else
- {
- $subtitle = "";
- }
-
- &addtimer ($timer_title,$title,$subtitle,$channel,$time,$Program{$title}{$channel}{$time}{duration},$prio,0,$marginstart_torecord[$counter],$marginstop_torecord[$counter]);
- last;
- }
- }
- }
+sub process_torecord {
+ my ($subtitle, $description, $prio, $lifetime, $timertitle, $counter);
+ foreach $title (sort keys %Program) {
+ foreach $channel (sort keys %{%Program->{$title}}) {
+ foreach $time (sort {$a <=> $b} keys %{%Program->{$title}->{$channel}}) {
+
+ $counter = &testtimer("torecord", $title, $channel, $time);
+ if ($counter ne "Nothing") {
+
+ # What Priority
+ if ($torecord{prio}[$counter]) {
+ $prio = $torecord{prio}[$counter];
+ }
+ else {
+ $prio = 50;
+ }
+
+ # What Lifetime
+ if ($torecord{lifetime}[$counter]) {
+ $lifetime = $torecord{lifetime}[$counter];
+ }
+ else {
+ $lifetime = 50;
+ }
+
+ # What Title to use for the timer
+ if ($torecord{timertitle}[$counter]) {
+ $timertitle = $torecord{timertitle}[$counter]
}
+ elsif ($torecord{title}[$counter]) {
+ $timertitle = $torecord{title}[$counter]
+ }
+ else {
+ $timertitle = $title;
+ }
+
+ # What subtitle to use
+ if ($Program{$title}{$channel}{$time}{subtitle}) {
+ $subtitle = $Program{$title}{$channel}{$time}{subtitle};
+ }
+ else {
+ $subtitle = "";
+ }
+
+ # What Description to use
+ if ($Program{$title}{$channel}{$time}{description}) {
+ $description = $Program{$title}{$channel}{$time}{description};
+ }
+ else {
+ $description = "";
+ }
+
+ &addtimer ($timertitle,$title,$subtitle,$description,$channel,$time,$Program{$title}{$channel}{$time}{duration},$prio,$lifetime,0,$torecord{marginstart}[$counter],$torecord{marginstop}[$counter]);
+ }
}
+ }
}
+}
-# Open the connection to VDR
-sub initsocket
- {
- my ($Dest, $Port) = split (/\:/,$Dest[$currentVDR - 1],2);
- my $iaddr = inet_aton($Dest);
- my $paddr = sockaddr_in($Port, $iaddr);
-
- socket(SOCKET, PF_INET, SOCK_STREAM, getprotobyname('tcp'));
- connect(SOCKET, $paddr) or sub_die ("Can't connect to VDR\n");
- select(SOCKET); $| = 1;
- select(STDOUT);
-
- while (<SOCKET>) {
- last if substr($_, 3, 1) ne "-";
- }
+# Test if a torecord/deepblack Entry matches the current EPG-Data-Field
+sub testtimer {
+ my ($context) = shift;
+ my ($title) = shift;
+ my ($channel) = shift;
+ my ($time) = shift;
+ my ($counter, $rContext);
+
+ if ($context eq "torecord") {
+ $rContext = \%torecord;
+ } elsif ($context eq "deepblack") {
+ $rContext = \%deepblack;
+ } else {
+ die ("Illegal Context");
}
-# Send a command to VDR and read back the result
-sub GetSend
- {
- my ($command, @retval);
-
- while ($command = shift)
- {
- print SOCKET "$command\r\n";
- while (<SOCKET>) {
- (@retval) = (@retval, $_);
- last if substr($_, 3, 1) ne "-";
+ if ($debug & 64) {
+ print "\n";
+ print "Context: \"$context\"\nTitle: \"$title\"\n";
+ print "Subtitle: \"$Program{$title}{$channel}{$time}{subtitle}\"\n" if ($Program{$title}{$channel}{$time}{subtitle});
+ print "Description \"$Program{$title}{$channel}{$time}{description}\"\n" if ($Program{$title}{$channel}{$time}{description});
+ print "Category \"$Program{$title}{$channel}{$time}{category}\"\n" if ($Program{$title}{$channel}{$time}{category});
+ print "Channel: $channel\n";
+ print "Time: $time\n";
+ print "Duration: $Program{$title}{$channel}{$time}{duration}\n";
+ }
+
+ # First look if any of the Title/Subtitle/Description REs match
+ if ($title =~ /$$rContext{titleRE}/i) {
+ print "Title hit\n" if ($debug & 64);
+ }
+ elsif ($Program{$title}{$channel}{$time}{subtitle} && $Program{$title}{$channel}{$time}{subtitle} =~ /$$rContext{subtitleRE}/i) {
+ print "SubTitle hit\n" if ($debug & 64);
+ }elsif ($Program{$title}{$channel}{$time}{subtitle} && $test_subtitle_movie && $Program{$title}{$channel}{$time}{subtitle} =~ /$subtitle_movie/) {
+ print "SubTitle-Movie hit\n" if ($debug & 64);
+ }
+ elsif ($Program{$title}{$channel}{$time}{description} && $Program{$title}{$channel}{$time}{description} =~ /$$rContext{descriptionRE}/i) {
+ print "Description hit\n" if ($debug & 64);
+ } else {
+ # No "Fast"-hit. Exiting
+ return "Nothing";
+ }
+
+ # Now look if we have a "exact" hit
+ print "In Exact Hit Loop\n" if ($debug & 64);
+ foreach my $counter (0 .. $$rContext{timercount}) {
+
+ print "Before Title Match\n" if ($debug & 64);
+ if ($$rContext{title}[$counter]) {
+ print "In Title Match \"$$rContext{title}[$counter]\"\n" if ($debug & 64);
+ if (!($title =~ /$$rContext{title}[$counter]/i)) {
+ print "Title rejected\n" if ($debug & 64);
+ next;
+ }
+ }
+
+ print "Before Subtitle Match\n" if ($debug & 64);
+ if ($$rContext{subtitle}[$counter]) {
+ print "In Subtitle Match \"$$rContext{subtitle}[$counter]\"\n" if ($debug & 64);
+ if ($Program{$title}{$channel}{$time}{subtitle}) {
+ if ($$rContext{subtitle}[$counter] =~ /^movie$/i) {
+ if (!($Program{$title}{$channel}{$time}{subtitle} =~ /$subtitle_movie/i)) {
+ print "Subtitle rejected 1\n" if ($debug & 64);
+ next;
+ }
+ }
+ elsif ($$rContext{subtitle}[$counter] =~ /^\!movie$/i) {
+ if (($Program{$title}{$channel}{$time}{subtitle} =~ /$subtitle_movie/i)) {
+ print "Subtitle rejected 2\n" if ($debug & 64);
+ next;
+ }
+ }
+ elsif (!($Program{$title}{$channel}{$time}{subtitle} =~ /$$rContext{subtitle}[$counter]/i)) {
+ print "Subtitle rejected 3\n" if ($debug & 64);
+ next;
+ }
+ } else {
+ # We had a Subtitle, but epg.data did not have a subtitle for this record so no chance to record this
+ print "Subtitle rejected 4\n" if ($debug & 64);
+ next;
+ }
+ }
+
+ print "Before Description Match\n" if ($debug & 64);
+ if ($$rContext{description}[$counter]) {
+ print "In Description Match \"$$rContext{description}[$counter]\"\n" if ($debug & 64);
+ if ($Program{$title}{$channel}{$time}{description}) {
+ if (!($Program{$title}{$channel}{$time}{description} =~ /$$rContext{description}[$counter]/i)) {
+ print "Description rejected 1\n" if ($debug & 64);
+ next;
+ }
+ }
+ elsif (!$$rContext{title}[$counter] && !$$rContext{subtitle}[$counter]) {
+ print "Description rejected 2\n" if ($debug & 64);
+ next;
+ }
+ }
+
+ print "Before Category Match\n" if ($debug & 64);
+ if ($$rContext{category}[$counter]) {
+ print "In Category Match \"$$rContext{category}[$counter]\"\n" if ($debug & 64);
+ if ($Program{$title}{$channel}{$time}{category}) {
+ my ($left, $right);
+ ($left, $right) = split (/\//, $$rContext{category}[$counter]);
+ if ($left) {
+ print "In Category Match Left \"$left\"\n" if ($debug & 64);
+ if (!($Program{$title}{$channel}{$time}{category} =~ /^$left\//)) {
+ print "Category rejected 1\n" if ($debug & 64);
+ next;
+ }
+ }
+ if ($right) {
+ print "In Category Match Right \"$right\"\n" if ($debug & 64);
+ if (!($Program{$title}{$channel}{$time}{category} =~ /\/$right$/)) {
+ print "Category rejected 2\n" if ($debug & 64);
+ next;
+ }
+ }
+ } else {
+ # We had a Category, but the epg.data not. So discard this Entry
+ print "Category rejected 3\n" if ($debug & 64);
+ next;
+ }
+ }
+
+ print "Before Channel Match\n" if ($debug & 64);
+ if ($$rContext{channel}[$counter]) {
+ print "In Channel Match Whitelist-Mode \"$$rContext{channel}[$counter]\"\n" if ($debug & 64);
+ if (!($channel =~ /$$rContext{channel}[$counter]/)) {
+ print "Channel rejected\n" if ($debug & 64);
+ next;
+ }
+ }
+
+ if ($$rContext{blackchannel}[$counter]) {
+ print "In Channel Match Blacklist-Mode \"$$rContext{blackchannel}[$counter]\"\n" if ($debug & 64);
+ if ($channel =~ /$$rContext{blackchannel}[$counter]/) {
+ print "Channel rejected\n" if ($debug & 64);
+ next;
+ }
+ }
+
+ print "Before Timeframe Match\n" if ($debug & 64);
+ if ($$rContext{timeframe}[$counter]) {
+ print "In Timeframe Match \"$$rContext{timeframe}[$counter]\"\n" if ($debug & 64);
+ my (@time, $time2, $ctime, $ctime2);
+ @time = GetTime($time);
+ $time2 = "$time[0]$time[1]";
+
+ ($ctime, $ctime2) = split (/\-/,$$rContext{timeframe}[$counter]);
+
+ if (!$ctime) {
+ $ctime = "0";
+ }
+ if (!$ctime2) {
+ $ctime2 = "2400";
+ }
+
+ if ($ctime < $ctime2) {
+ if (!($time2 >= $ctime && $time2 <= $ctime2)) {
+ print "Timeframe rejected 1\n" if ($debug & 64);
+ next;
+ }
+ }
+ else {
+ if (!(($time2 >= $ctime && $time2 <= "2400") || ($time2 >= "0" && $time2 <= $ctime2))) {
+ print "Timeframe rejected 2\n" if ($debug & 64);
+ next;
}
}
+ }
+
+ print "Before Weekday Match\n" if ($debug & 64);
+ if ($$rContext{weekday}[$counter]) {
+ print "In Weekday Match \"$$rContext{weekday}\"\n" if ($debug & 64);
+ my ($wday);
+ $wday = getWDay($time);
+ $$rContext{weekday}[$counter] =~ /(.)(.)(.)(.)(.)(.)(.)/;
+ if ($$wday eq "-") {
+ print "Weekday rejected\n" if ($debug & 64);
+ next;
+ }
+ }
+
+ print "Before Minlength Match\n" if ($debug & 64);
+ if ($$rContext{minlength}[$counter]) {
+ print "In Minlength Match \"$$rContext{minlength}[$counter]\"\n" if ($debug & 64);
+ if ($Program{$title}{$channel}{$time}{duration} < $$rContext{minlength}[$counter]) {
+ print "Minlength rejected\n" if ($debug & 64);
+ next;
+ }
+ }
- foreach my $retval (@retval)
- {
- $retval =~ s/\x0d//g;
+ print "Before Maxlength Match\n" if ($debug & 64);
+ if ($$rContext{maxlength}[$counter]) {
+ print "In Maxlength Match \"$$rContext{maxlength}[$counter]\"\n" if ($debug & 64);
+ if ($Program{$title}{$channel}{$time}{duration} > $$rContext{maxlength}[$counter]) {
+ print "Maxlength rejected\n" if ($debug & 64);
+ next;
}
- return (@retval);
+ }
+
+ # All test passed. Accept this timer
+ print "All Tests passed entry accepted/blacklisted\n" if ($debug & 64);
+ return ($counter);
+ }
+ # Foreach ran out without a hit
+ return "Nothing";
+}
+
+# Open the connection to VDR
+sub initsocket {
+ my ($Dest, $Port) = split (/\:/,$Dest[$currentVDR - 1],2);
+ my $iaddr = inet_aton($Dest);
+ my $paddr = sockaddr_in($Port, $iaddr);
+ my $Timeout = 10; # max. seconds to wait for response
+
+ $SIG{ALRM} = sub { die("Timeout while connecting to VDR"); };
+ alarm($Timeout);
+
+ socket(SOCKET, PF_INET, SOCK_STREAM, getprotobyname('tcp'));
+ connect(SOCKET, $paddr) or die ("Can't connect to VDR\n");
+ select(SOCKET); $| = 1;
+ select(STDOUT);
+
+ while (<SOCKET>) {
+ last if substr($_, 3, 1) ne "-";
}
+ alarm(0);
+}
+
+# Send a command to VDR and read back the result
+sub GetSend {
+ my ($command, @retval);
+
+ while ($command = shift) {
+ print SOCKET "$command\r\n";
+ while (<SOCKET>) {
+ s/\x0d//g;
+ (@retval) = (@retval, $_);
+ last if substr($_, 3, 1) ne "-";
+ }
+ }
+ return (@retval);
+}
# Close the socket to VDR
-sub closesocket
- {
- print SOCKET "Quit\r\n";
- close(SOCKET);
- }
+sub closesocket {
+ print SOCKET "Quit\r\n";
+ close(SOCKET);
+}
# Fetch the timers-List from VDR via SVDR and process it.
-sub fetchVDRTimers
- {
- my (@timers, $timer, $position, $active, $channel, $day, $start, $end, $prio, $ttl, $title, $subtitle, $minute, $duration);
- my ($utime, $utime2);
-
- # First fetch the timers-list from VDR
- @timers = GetSend ("lstt");
-
- foreach $timer (@timers)
- {
-# $timer =~ s/\x0d//g;
- chomp $timer;
- # a Valid Timer-line beginns with "250"
- if ($timer =~ s/250-|250\s//)
- {
- # Extract the Position in front of the line
- ($position, $timer) = split (/\s/,$timer,2);
-
-# print "Position: \"$position\" Timer: \"$timer\"\n";
- # Split the : seperated values
- ($active, $channel, $day, $start, $end, $prio, $ttl, $title, $subtitle) = split (/\:/,$timer,9);
-
- my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
-
- # If the string is exactly 7 char wide, then its a "repeating"-timer
- if ($active >= 1)
- {
- if ($day =~ /(.)(.)(.)(.)(.)(.)(.)/)
- {
- my (@days);
- @days = ($1, $2, $3, $4, $5, $6, $7);
- ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
-
- $start =~ /(\d\d)(\d\d)/;
- $hour = $1;
- $minute = $2;
- $utime = timelocal 0, $minute, $hour, $mday, $mon, $year;
- $end =~ /(\d\d)(\d\d)/;
- $hour = $1;
- $minute = $2;
- $utime2 = timelocal 0, $minute, $hour, $mday, $mon, $year;
- if ($end < $start)
- {
- $utime2 += 24*60*60;
- }
- $duration = $utime2 - $utime;
-
- # "Normalize" the timestamp to monday
- $utime = $utime - ($wday * 24 * 60 *60);
-
- foreach my $num (0 .. $#days)
- {
- if ($days[$num] ne "-")
- {
- my $utime3;
- # Todays before today will be shifted in the next week
- if (($num + 1) < $wday)
- {
- $utime3 = $utime + (($num + 7 + 1) * 24 * 60 * 60);
- }
- else
- {
- $utime3 = $utime + (($num + 1) * 24 * 60 * 60);
- }
- &addtimer ($title,$title,$subtitle,$channels[$channel],$utime3,$duration,$prio,"R$position",0,0);
- }
- }
- }
-
- # When the Day-Value is between 1 and 31, then its a "One time" Timer
- elsif (($day >= 1) && ($day <= 31))
- {
- if ($active == "2")
- {
- $position += 1000000;
- }
- # When the Day is before the Current-Day, then the Timer is for the next month
- if ($day < $mday)
- {
- $mon++;
- if ($mon == 12)
- {
- $mon = 0;
- $year ++;
- }
- }
- $start =~ /(\d\d)(\d\d)/;
- $hour = $1;
- $minute = $2;
- $utime = timelocal 0, $minute, $hour, $day, $mon, $year;
- $end =~ /(\d\d)(\d\d)/;
- $hour = $1;
- $minute = $2;
- $utime2 = timelocal 0, $minute, $hour, $day, $mon, $year;
- if ($end < $start)
- {
- $utime2 += 24*60*60;
- }
- $duration = $utime2 - $utime;
-
- &addtimer ($title,$title,$subtitle,$channels[$channel],$utime,$duration,$prio,$position,0,0);
- }
+sub fetchVDRTimers {
+ my (@timers, $timer, $position, $active, $channel, $day, $start, $end, $prio, $lifetime, $title, $subtitle, $minute, $duration);
+ my ($utime, $utime2);
+
+ # First fetch the timers-list from VDR
+ @timers = GetSend ("lstt");
+
+ foreach $timer (@timers) {
+ chomp $timer;
+ # a Valid Timer-line beginns with "250"
+ if ($timer =~ s/250-|250\s//) {
+ # Extract the Position in front of the line
+ ($position, $timer) = split (/\s/,$timer,2);
+
+# print "Position: \"$position\" Timer: \"$timer\"\n";
+ # Split the : seperated values
+ ($active, $channel, $day, $start, $end, $prio, $lifetime, $title, $subtitle) = split (/\:/,$timer,9);
+
+ my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
+
+ # If the string is exactly 7 char wide, then its a "repeating"-timer
+ if ($active >= 1) {
+ if ($day =~ /(.)(.)(.)(.)(.)(.)(.)/) {
+ my (@days);
+ @days = ($1, $2, $3, $4, $5, $6, $7);
+ ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
+
+ $start =~ /(\d\d)(\d\d)/;
+ $hour = $1;
+ $minute = $2;
+ $utime = timelocal 0, $minute, $hour, $mday, $mon, $year;
+ $end =~ /(\d\d)(\d\d)/;
+ $hour = $1;
+ $minute = $2;
+ $utime2 = timelocal 0, $minute, $hour, $mday, $mon, $year;
+ if ($end < $start) {
+ $utime2 += 24*60*60;
+ }
+ $duration = $utime2 - $utime;
+
+ # "Normalize" the timestamp to monday
+ $utime = $utime - ($wday * 24 * 60 *60);
+
+ foreach my $num (0 .. $#days) {
+ if ($days[$num] ne "-") {
+ my $utime3;
+ # Days before today will be shifted in the next week
+ if (($num + 1) < $wday) {
+ $utime3 = $utime + (($num + 7 + 1) * 24 * 60 * 60);
}
+ else {
+ $utime3 = $utime + (($num + 1) * 24 * 60 * 60);
+ }
+ &addtimer ($title,$title,$subtitle,"",$channels[$channel],$utime3,$duration,$prio,$lifetime,"R$position",0,0);
+ }
+ }
+ }
+
+ # When the Day-Value is between 1 and 31, then its a "One time" Timer
+ elsif (($day >= 1) && ($day <= 31)) {
+ if ($active == "2") {
+ $position += 1000000;
+ }
+ # When the Day is before the Current-Day, then the Timer is for the next month
+ if ($day < $mday) {
+ $mon++;
+ if ($mon == 12) {
+ $mon = 0;
+ $year ++;
+ }
}
+ $start =~ /(\d\d)(\d\d)/;
+ $hour = $1;
+ $minute = $2;
+ $utime = timelocal 0, $minute, $hour, $day, $mon, $year;
+ $end =~ /(\d\d)(\d\d)/;
+ $hour = $1;
+ $minute = $2;
+ $utime2 = timelocal 0, $minute, $hour, $day, $mon, $year;
+ if ($end < $start) {
+ $utime2 += 24*60*60;
+ }
+ $duration = $utime2 - $utime;
+
+ &addtimer ($title,$title,$subtitle,"",$channels[$channel],$utime,$duration,$prio,$lifetime,$position,0,0);
+ }
}
+ }
}
+}
# Parse file "epg.data"
-sub initepgdata
- {
- open (FI,"epg.data") or sub_die ("Can't open file \"epg.data\"\n");
-
- while (<FI>)
- {
- # Begin Channel
- if (/^C\s(\d+)\s+(.+)/)
- {
- $channel = $2;
- while (<FI>)
- {
- # End Channel
- if (/^c$/)
- {
- last;
- }
- # Begin Timer
- elsif (/^E\s(\d+)\s+(\d+)\s+(\d+)$/)
- {
- # Undef this Variables because it is possibel that not every timer uses this values
- undef $duration;
- undef $subtitle;
- undef $description;
-
- $time=$2;
- $duration=$3;
- }
- # Title
- elsif (/^T\s(.*)/)
- {
- $title = $1;
- }
- # Subtitle
- elsif (/^S\s(.*)/)
- {
- $subtitle=$1;
- }
- # Description
- elsif (/^D\s(.*)/)
- {
- $description=$1;
- }
- # End Timer
- elsif (/^e$/)
- {
- # Only accept timers that are in the future
- if ($time < time)
- {
- next;
- }
-
- # Work around the diffrent Bugs in the data
- &correct_epg_data();
-
- # Check if the title is in the DEEP-Blacklist
- if ($title =~ /$title_deepblack/i)
- {
- next;
- }
-
- # Check if the Title & Subtitle is in the Done-List
- if ($title =~ /$title_done/)
- {
- if ($subtitle)
- {
- if ($subtitle =~ /$subtitle_done/)
- {
- next;
- }
- }
- }
-
- $Program{$title}{$channel}{$time}{duration}=$duration;
- if ($subtitle)
- {
- $Program{$title}{$channel}{$time}{subtitle}=$subtitle;
- }
- if ($description)
- {
- $Program{$title}{$channel}{$time}{description}=$description;
- }
- }
- }
+sub initepgdata {
+ open (FI,"epg.data") or die ("Can't open file \"epg.data\"\n");
+
+ while (<FI>) {
+ # Begin Channel
+ if (/^C\s(\d+)\s+(.+)/) {
+ $channel=$2;
+ while (<FI>) {
+ # End Channel
+ if (/^c$/) {
+ last;
+ }
+ # Begin Timer
+ elsif (/^E\s(\d+)\s+(\d+)\s+(\d+)$/) {
+ # Undef this Variables because it is possibel that not every timer uses this values
+ undef $duration;
+ undef $subtitle;
+ undef $description;
+ undef $category;
+
+ $time=$2;
+ $duration=$3;
+ }
+ # Title
+ elsif (/^T\s(.*)/) {
+ $title=$1;
+ }
+ # Subtitle
+ elsif (/^S\s(.*)/) {
+ $subtitle=$1;
}
+ # Description
+ elsif (/^D\s(.*)/) {
+ $description=$1;
+ }
+ elsif (/^K\s(.*)/) {
+ $category=$1;
+ }
+ # End Timer
+ elsif (/^e$/) {
+ # Only accept timers that are in the future
+ if ($time < time) {
+ next;
+ }
+ # Only accept timers that are at least 2 Seconds long
+ if ($duration <= 1) {
+ next;
+ }
+
+ # Work around the different Bugs in the data
+ &correct_epg_data();
+
+ # Check if the Title & Subtitle is in the Done-List (Only if Subtitle exists)
+ if ($subtitle && $title =~ /$title_done/ && $subtitle =~ /$subtitle_done/) {
+ next;
+ }
+
+ $Program{$title}{$channel}{$time}{duration}=$duration;
+ if ($subtitle) {
+ $Program{$title}{$channel}{$time}{subtitle}=$subtitle;
+ }
+ if ($description) {
+ $Program{$title}{$channel}{$time}{description}=$description;
+ }
+ if ($category) {
+ $Program{$title}{$channel}{$time}{category}=$category;
+ }
+ # Check if the title is in the DEEP-Blacklist
+ if (&testtimer("deepblack", $title, $channel, $time) ne "Nothing") {
+ print "Deepblack: \"$title\"" if ($debug & 64);
+ print " $subtitle" if ($debug & 64 && $subtitle);
+ print "\n" if ($debug & 64);
+ &delprogram ($title, $channel, $time);
+ }
+ }
+ }
}
- close (FI);
- }
+ }
+ close (FI);
+}
# What is a Movie (When correctly stored into Subtitle)
-sub initmovie
- {
- my (@list,$list);
- open (FI,"$ENV{HOME}/.master-timer/subtitle-movie") or return;
- @list = <FI>;
- close(FI);
-
- foreach $list (@list)
- {
- chomp $list;
- }
- $subtitle_movie = join ('|',@list);
+sub initmovie {
+ my (@list,$list);
+ open (FI,"${configdir}/subtitle-movie") or return;
+ @list = <FI>;
+ close(FI);
+
+ foreach $list (@list) {
+ chomp $list;
}
+ $subtitle_movie = join ('|',@list);
+}
-# What should be blacklistet
-sub initblacklist
- {
- my (@list,$list);
- if (open (FI,"$ENV{HOME}/.master-timer/deepblack"))
- {
- @list = <FI>;
- close(FI);
-
- foreach $list (@list)
- {
- chomp $list;
- }
- $title_deepblack = join ('|',@list);
- }
- else
- {
- $title_deepblack = "^\$";
+# What is already recorded/Should not be recorded
+sub initdone {
+ my (@list,$list, %title_done, %subtitle_done, $title_temp, $subtitle_temp);
+ open (FI,"${configdir}/done") or return;
+ @list = <FI>;
+ close (FI);
+
+ foreach $list (@list) {
+ chomp $list;
+ ($title_temp,$subtitle_temp) = split (/\|/,$list);
+ if ($title_temp) {
+ $title_done{"^\Q$title_temp\E\$"} = 1;
+ }
+ if ($subtitle_temp) {
+ $subtitle_done{"^\Q$subtitle_temp\E\$"} = 1;
+ }
+ }
+ $title_done = join ('|',sort keys %title_done);
+ $subtitle_done = join ('|',sort keys %subtitle_done);
+}
+
+sub processdone {
+ # Now delete Timers in VDR that are already in the done-List
+ my ($list, @list, $position, $timer, $active, $g, $title, $subtitle, $counter, @todel);
+ $counter = 0;
+ @list = GetSend ("LSTT");
+
+ foreach $timer (@list) {
+ chomp $timer;
+ if ($timer =~ s/250-|250\s//) {
+ ($position, $timer) = split (/\s/,$timer,2);
+ # Split the : seperated values
+ ($active, $g, $g, $g, $g, $g, $g, $title, $subtitle) = split (/\:/,$timer,9);
+ if ($active == 2) {
+ # Title: "Shakespeare in Love"||Subtitle: "Romanze"
+ my ($ctitle, $csubtitle);
+ if ($subtitle && $subtitle =~ /^Title\:\s\"(.*)\"\|\|Subtitle\:\s\"(.*)\"/) {
+ $title = $1;
+ $subtitle = $2;
+ if ($subtitle) {
+ my (@titles, @subtitles, $num, $hit);
+ undef $hit;
+ @titles = split (/\~/,$title);
+ @subtitles = split (/\~/,$subtitle);
+ foreach $num (0 .. $#titles) {
+ if ($titles[$num] =~ /$title_done/ && $subtitles[$num] =~ /$subtitle_done/) {
+ $hit = 1;
+ }
+ else {
+ undef $hit;
+ last;
+ }
+ }
+
+ if ($hit) {
+ my ($result);
+ print "Delete Timer: $title $subtitle\n" if ($debug & 4);
+ $position -= $counter;
+ ($result) = GetSend ("DELT $position");
+ print "Result: $result" if ($debug & 4);
+ if ($result =~ /^250/) {
+ $counter++;
+ }
+ }
+ }
+ }
}
+ }
}
+}
-# What is already recorded/Should not be recorded
-sub initdone
- {
- my (@list,$list, %title_done, %subtitle_done, $title_temp, $subtitle_temp);
- if (open (FI,"$ENV{HOME}/.master-timer/done"))
- {
- @list = <FI>;
- close (FI);
-
- foreach $list (@list)
- {
- chomp $list;
- ($title_temp,$subtitle_temp) = split (/\|/,$list);
- if ($title_temp)
- {
- $title_done{"^$title_temp\$"} = 1;
- }
- if ($subtitle_temp)
- {
- $subtitle_done{"^$subtitle_temp\$"} = 1;
- }
+# What should be recorded
+sub inittorecord {
+ my ($context) = shift;
+ my ($rContext);
+ my (@title_list, @subtitle_list, @description_list, $line);
+ my (%Input);
+ my $counter = 0;
+
+ if ($context eq "torecord") {
+ $rContext = \%torecord;
+ open (FI,"${configdir}/${context}") or die ("Can't open file \"$context\"\n");
+ } elsif ($context eq "deepblack") {
+ $rContext = \%deepblack;
+ open (FI,"${configdir}/${context}") or return;
+ } else {
+ die ("Illegal Context");
+ }
+
+
+ outer: while (<FI>) {
+ chomp if ($_);
+ if ($_ && !(/^\#/) && /^\[.*\]$/) {
+ $line = $.;
+ undef %Input;
+ while (<FI>) {
+ chomp;
+ if ($_ && !(/^\#/)) {
+ if (/^\[.*?\]$/) {
+ last;
}
- $title_done = join ('|',sort keys %title_done);
- $subtitle_done = join ('|',sort keys %subtitle_done);
-
- # Ein paar Zeichen Escapen
- $title_done =~ s/\?/\\\?/g;
- $title_done =~ s/\+/\\\+/g;
- $subtitle_done =~ s/\?/\\\?/g;
- $subtitle_done =~ s/\+/\\\+/g;
-
- # Now delete Timers in VDR that are already in the done-List
- my ($position, $timer, $active, $g, $title, $subtitle, $counter, @todel);
- $counter = 0;
- @list = GetSend ("LSTT");
-
- foreach $timer (@list)
- {
-# $timer =~ s/0x0d//g;
- chomp $timer;
- if ($timer =~ s/250-|250\s//)
- {
- ($position, $timer) = split (/\s/,$timer,2);
- # Split the : seperated values
- ($active, $g, $g, $g, $g, $g, $g, $title, $subtitle) = split (/\:/,$timer,9);
- if ($active == 2)
- {
- # Title: "Shakespeare in Love"||Subtitle: "Romanze"
- my ($ctitle, $csubtitle);
- if ($subtitle && $subtitle =~ /^Title\:\s\"(.*)\"\|\|Subtitle\:\s\"(.*)\"/)
- {
- $title = $1;
- $subtitle = $2;
- if ($subtitle)
- {
- my (@titles, @subtitles, $num, $hit);
- undef $hit;
- @titles = split (/\~/,$title);
- @subtitles = split (/\~/,$subtitle);
- foreach $num (0 .. $#titles)
- {
- if ($titles[$num] =~ /$title_done/ && $subtitles[$num] =~ /$subtitle_done/)
- {
- $hit = 1;
- }
- else
- {
- undef $hit;
- last;
- }
- }
-
- if ($hit)
- {
- my ($result);
- print "Delete Timer: $title $subtitle\n" if ($debug & 4);
- $position -= $counter;
- ($result) = GetSend ("DELT $position");
- print "Result: $result" if ($debug & 4);
- if ($result =~ /^250/)
- {
- $counter++;
- }
- }
- }
- }
- }
- }
+
+ my ($key, $value);
+ ($key, $value) = split (/\s+=\s+/);
+
+ if ($key =~ /^title$/i) {
+ if ($Input{title}) {
+ $Input{title} .= "|$value";
+ } else {
+ $Input{title} = $value;
+ }
+ print "Titel = $value\n" if ($debug & 16);
+ }
+ elsif ($key =~ /^subtitle$/i) {
+ if ($Input{subtitle}) {
+ $Input{subtitle} .= "|$value";
+ } else {
+ $Input{subtitle} = $value;
+ }
+ print "Subtitel = $value\n" if ($debug & 16);
+ }
+ elsif ($key =~ /^description$/i) {
+ if ($Input{description}) {
+ $Input{description} .= "|$value";
+ } else {
+ $Input{description} = $value;
+ }
+ print "Description = $value\n" if ($debug & 16);
+ }
+ elsif ($key =~ /^category$/i) {
+ $Input{category} = $value;
+ print "Category = $value\n" if ($debug & 16);
+ }
+ elsif ($key =~ /^channel$/i) {
+ if ($Input{channel}) {
+ $Input{channel} .= "|^$value\$";
+ } else {
+ $Input{channel} = $value;
+ }
+ print "Channel = $value\n" if ($debug & 16);
+ }
+ elsif ($key =~ /^timeframe$/i) {
+ $Input{timeframe} = $value;
+ print "Timeframe = $value\n" if ($debug & 16);
}
+ elsif ($key =~ /^weekday$/i) {
+ $Input{weekday} = $value;
+ print "Weekday = $value\n" if ($debug & 16);
+ }
+ elsif ($key =~ /^minlength$/i) {
+ $Input{minlength} = $value;
+ print "Minlength = $value\n" if ($debug & 16);
+ }
+ elsif ($key =~ /^maxlength$/i) {
+ $Input{maxlength} = $value;
+ print "Maxlength = $value\n" if ($debug & 16);
+ }
+ elsif ($key =~ /^prio$/i) {
+ $Input{prio} = $value;
+ print "Prio = $value\n" if ($debug & 16);
+ }
+ elsif ($key =~ /^lifetime$/i) {
+ $Input{lifetime} = $value;
+ print "Lifetime = $value\n" if ($debug & 16);
+ }
+ elsif ($key =~ /^timertitle$/i) {
+ $Input{timertitle} = $value;
+ print "Timertitel = $value\n" if ($debug & 16);
+ }
+ elsif ($key =~ /^margin$/i) {
+ $Input{margin} = $value;
+ print "Margin = $value\n" if ($debug & 16);
+ }
+ elsif ($key =~ /^instance$/i) {
+ $Input{instance} = $value;
+ print "Instance = $value\n" if ($debug & 16);
+ } else {
+ print "Unkown Key: \"$key\" with Value: \"$value\"\n";
+ }
+ }
}
- }
-# What should be recorded
-sub inittorecord
- {
- my (@list, $list, $title, $subtitle, $description, $channel, $timeframe, $prio, $timer_title, $margin, $machine, @title_list, @subtitle_list, @description_list);
- my $counter = 0;
- open (FI,"$ENV{HOME}/.master-timer/torecord") or sub_die ("Can't open file \"torecord\"\n");
- @list = <FI>;
- close(FI);
-
- foreach $list (0 .. $#list)
- {
- chomp $list[$list];
- if ($list[$list] && !($list[$list] =~ /^\#/))
- {
- ($title, $subtitle, $description, $channel, $timeframe, $prio, $timer_title, $margin, $machine) = split (/\|/,$list[$list]);
-
- # Accept torecord only if it is for the current machine
- if ((!$machine && $currentVDR == 1) || $machine == $currentVDR)
- {
- if ($title)
- {
- $title_torecord[$counter] = $title;
- $title_list[$#title_list + 1] = $title;
- }
- if ($subtitle)
- {
- $subtitle_torecord[$counter] = $subtitle;
- $subtitle_list[$#subtitle_list + 1] = $subtitle;
- }
- if ($description)
- {
- $description_torecord[$counter] = $description;
- $description_list[$#description_list + 1] = $description;
- }
- if ($channel)
- {
- my (@temp);
- @temp = split (/\;/,$channel);
- foreach (0 .. $#temp)
- {
- $channel_torecord[$counter][$_] = $temp[$_];
- }
- }
- if ($timeframe)
- {
- $timeframe_torecord[$counter] = $timeframe;
- }
- if ($prio)
- {
- $prio_torecord[$counter] = $prio;
- }
- else
- {
- $prio_torecord[$counter] = $default_prio;
- }
- if ($timer_title)
- {
- $timer_title_torecord[$counter] = $timer_title;
- }
- if ($margin)
- {
- my ($start, $stop);
- ($start, $stop) = split (/;/,$margin, 2);
- $marginstart_torecord[$counter] = $start if ($start);
- $marginstop_torecord[$counter] = $stop if ($stop);
- }
- # Set Default-Margins if not margins defined
- $marginstart_torecord[$counter] = $marginstart if (!$marginstart_torecord[$counter]);
- $marginstop_torecord[$counter] = $marginstop if (!$marginstop_torecord[$counter]);
- $counter++;
- }
+ # Accept entry only if it is for the current instance or for "no" instance
+ if (($Opts{s} && $Input{instance} && $Input{instance} eq "s") || !$Input{instance} || ($Input{instance} ne "s" && $Input{instance} == $currentVDR)) {
+ # Accept entry only if at least a Title/Subtitle/Description is provied
+ if (!$Input{title} && !$Input{subtitle} && !$Input{description}) {
+ print "No Title/Subtitle/Description Field. $context entry ignored. Block beginning at Line $line\n";
+ redo outer;
+ }
+
+ if ($Input{title}) {
+ $$rContext{title}[$counter] = $Input{title};
+ $title_list[$#title_list + 1] = $Input{title};
+ }
+ if ($Input{subtitle}) {
+ if ($Input{subtitle} =~ /^movie$/i || $Input{subtitle} =~ /^\!movie$/i) {
+ $test_subtitle_movie = 1;
+ }
+ $$rContext{subtitle}[$counter] = $Input{subtitle};
+ $subtitle_list[$#subtitle_list + 1] = $Input{subtitle};
+ }
+ if ($Input{description}) {
+ $$rContext{description}[$counter] = $Input{description};
+ $description_list[$#description_list + 1] = $Input{description};
+ }
+ if ($Input{category}) {
+ $$rContext{category}[$counter] = $Input{category};
+ }
+ if ($Input{channel}) {
+ if ($Input{channel} =~ /\!/) {
+ $Input{channel} =~ s/\!//g;
+ $$rContext{blackchannel}[$counter] = $Input{channel};
+ } else {
+ $$rContext{channel}[$counter] = $Input{channel};
}
+ }
+ if ($Input{timeframe}) {
+ $$rContext{timeframe}[$counter] = $Input{timeframe};
+ }
+ if ($Input{weekday}) {
+ $$rContext{weekday}[$counter] = $Input{weekday};
+ }
+ if ($Input{minlength}) {
+ if ($Input{minlength} =~ /^(\d+)m$/) {
+ $Input{minlength} = $1 * 60
+ } elsif ($Input{minlength} =~ /^(\d+)h$/) {
+ $Input{minlength} = $1 * 60 * 60
+ }
+ $$rContext{minlength}[$counter] = $Input{minlength};
+ }
+ if ($Input{maxlength}) {
+ if ($Input{maxlength} =~ /^(\d+)m$/) {
+ $Input{maxlength} = $1 * 60
+ } elsif ($Input{maxlength} =~ /^(\d+)h$/) {
+ $Input{maxlength} = $1 * 60 * 60
+ }
+ $$rContext{maxlength}[$counter] = $Input{maxlength};
+ }
+ if ($Input{prio}) {
+ $$rContext{prio}[$counter] = $Input{prio};
+ }
+ if ($Input{lifetime}) {
+ $$rContext{lifetime}[$counter] = $Input{lifetime};
+ }
+ else {
+ $$rContext{prio}[$counter] = $default_prio;
+ }
+ if ($Input{timertitle}) {
+ $$rContext{timertitle}[$counter] = $Input{timertitle};
+ }
+ if ($Input{margin}) {
+ my ($start, $stop);
+ ($start, $stop) = split (/;/,$Input{margin}, 2);
+ $$rContext{marginstart}[$counter] = $start if ($start);
+ $$rContext{marginstop}[$counter] = $stop if ($stop);
+ }
+ # Set Default-Margins if no margins defined
+ $$rContext{marginstart}[$counter] = $marginstart if (!$$rContext{marginstart}[$counter]);
+ $$rContext{marginstop}[$counter] = $marginstop if (!$$rContext{marginstop}[$counter]);
+ $counter++;
+ if ($Input{instance}) {
+ $$rContext{instance}[$counter] = $Input{instance};
+ }
}
+ redo outer;
+ }
+ }
+
+ $$rContext{timercount} = $counter - 1;
+
+ $$rContext{titleRE} = join ('|',@title_list);
+ if ($$rContext{titleRE} && $$rContext{titleRE} =~ /\|.\|/) {
+ $$rContext{titleRE} = ".";
+ }
+ $$rContext{subtitleRE} = join ('|',@subtitle_list);
+ if ($$rContext{subtitleRE} && $$rContext{subtitleRE} =~ /\|.\|/) {
+ $$rContext{subtitleRE} = ".";
+ }
+ $$rContext{descriptionRE} = join ('|',@description_list);
+ if ($$rContext{descriptionRE} && $$rContext{descriptionRE} =~ /\|.\|/) {
+ $$rContext{descriptionRE} = ".";
+ }
+
+ if (!$$rContext{titleRE}) {
+ $$rContext{titleRE} = "^Dieseshierwirdgarantiertnieundnimmeraufirgendetwassinnvollesmatchen\$";
+ }
+ if (!$$rContext{subtitleRE}) {
+ $$rContext{subtitleRE} = "^Dieseshierwirdgarantiertnieundnimmeraufirgendetwassinnvollesmatchen\$";
+ }
+ if (!$$rContext{descriptionRE}) {
+ $$rContext{descriptionRE} = "^Dieseshierwirdgarantiertnieundnimmeraufirgendetwassinnvollesmatchen\$";
+ }
+}
+
+# Parse "LSTC"-Command of VDR
+sub initchannellist {
+ my ($counter, $chan, $garbage, $card, @temp_channels, $temp, $i);
- $num_torecord = $counter - 1;
+ @temp_channels = GetSend ("LSTC");
- $title_torecord = join ('|',@title_list);
- $subtitle_torecord = join ('|',@subtitle_list);
- $description_torecord = join ('|',@description_list);
+ foreach $i (0 .. $#temp_channels) {
+ $temp = $temp_channels[$i];
+ chomp $temp;
- if (!$title_torecord)
- {
- $title_torecord = "^Dieseshierwirdgarantiertnieundnimmeraufirgendetwassinnvollesmatchen\$";
+ if ($temp =~ s/250-|250\s//) {
+ ($counter, $temp) = split (/\s/,$temp,2);
+ ($chan, $garbage,$garbage, $garbage, $garbage, $garbage, $garbage, $card, $garbage) = split (/\:/,$temp);
+ $channels[$counter] = $chan;
+ $channels{$chan}{number} = $counter;
+ $channels{$chan}{card} = $card;
+ $counter++;
+ }
+ }
+}
+
+sub initconfigfile {
+ open (FI,"${configdir}/config") or return;
+ while (<FI>) {
+ s/\#.*//;
+ chomp;
+ if ($_) {
+ my ($key, $value);
+ ($key, $value) = split (/\s+=\s+/);
+ if ($key =~ /^debug$/i) {
+ $debug = $value;
+ print "Debug-Level = $value\n" if ($debug & 16);
}
- if (!$subtitle_torecord)
- {
- $subtitle_torecord = "^Dieseshierwirdgarantiertnieundnimmeraufirgendetwassinnvollesmatchen\$";
+ elsif ($key =~ /^marginstart$/i) {
+ print "Marginstart = $value\n" if ($debug & 16);
+ $marginstart = $value;
}
- if (!$description_torecord)
- {
- $description_torecord = "^Dieseshierwirdgarantiertnieundnimmeraufirgendetwassinnvollesmatchen\$";
+ elsif ($key =~ /^marginstop$/i) {
+ print "Marginstop = $value\n" if ($debug & 16);
+ $marginstop = $value;
}
- }
-
-# Parse the "channels.conf" of VDR
-sub initchannellist
- {
- my ($counter, $chan, $garbage, $card, @temp_channels, $temp, $i);
-
- @temp_channels = GetSend ("LSTC");
-
- foreach $i (0 .. $#temp_channels)
- {
- $temp = $temp_channels[$i];
-# $temp =~ s/\x0d//g;
- chomp $temp;
-
- if ($temp =~ s/250-|250\s//)
- {
- ($counter, $temp) = split (/\s/,$temp,2);
- ($chan, $garbage,$garbage, $garbage, $garbage, $garbage, $garbage, $card, $garbage) = split (/\:/,$temp);
- $channels[$counter] = $chan;
- $channels{$chan}{number} = $counter;
- $channels{$chan}{card} = $card;
- $counter++;
- }
+ elsif ($key =~ /^DVBCards$/i) {
+ print "DVB_Cards = $value\n" if ($debug & 16);
+ $DVB_cards = $value;
+ }
+ elsif ($key =~ /^defaultprio$/i) {
+ print "Default Priority = $value\n" if ($debug & 16);
+ $default_prio = $value;
+ }
+ elsif ($key =~ /^Dest$/i) {
+ print "Destination Host/IP:Port = $value\n" if ($debug & 16);
+ @Dest = split (/\s+/,$value);
+ }
+ elsif ($key =~ /^jointimers$/i) {
+ print "Join Timers = $value\n" if ($debug & 16);
+ $jointimers = $value;
+ }
+ elsif ($key =~ /^description$/i) {
+ print "Description = $value\n" if ($debug & 16);
+ $Description = $value;
+ }
+ else {
+ print "Unkown Key: \"$key\" with Value: \"$value\"\n";
}
+ }
}
+ print "End Config\n" if ($debug & 16);
+}
-sub initconfigfile
- {
- open (FI,"$ENV{HOME}/.master-timer/config") or return;
- while (<FI>)
- {
- s/\#.*//;
- chomp;
- if ($_)
- {
- my ($key, $value);
- ($key, $value) = split (/\s+=\s+/);
- if ($key =~ /^debug$/i)
- {
- $debug = $value;
- print "Debug-Level = $value\n" if ($debug & 16);
- }
- elsif ($key =~ /^marginstart$/i)
- {
- print "Marginstart = $value\n" if ($debug & 16);
- $marginstart = $value;
- }
- elsif ($key =~ /^marginstop$/i)
- {
- print "Marginstop = $value\n" if ($debug & 16);
- $marginstop = $value;
- }
- elsif ($key =~ /^DVBCards$/i)
- {
- print "DVB_Cards = $value\n" if ($debug & 16);
- $DVB_cards = $value;
- }
- elsif ($key =~ /^defaultprio$/i)
- {
- print "Default Priority = $value\n" if ($debug & 16);
- $default_prio = $value;
- }
- elsif ($key =~ /^Dest$/i)
- {
- print "Destination Host/IP:Port = $value\n" if ($debug & 16);
- @Dest = split (/\s+/,$value);
- }
- elsif ($key =~ /^jointimers$/i)
- {
- print "Join Timers = $value\n" if ($debug & 16);
- $jointimers = $value;
- }
- else
- {
- print "Unkown Key: \"$key\" with Value: \"$value\"\n";
- }
- }
- }
- print "End Config\n" if ($debug & 16);
+sub initcommandline() {
+ my $Usage = qq{
+Usage: $0 [options] [Instance]...
+
+Options: -d hostname:Port hostname/ip:Port (localhost:2001)
+ -c configdir Directory where all config files are located
+ (~/.master-timer)
+ -i instance Which VDR-Instance, from the config-file, should be
+ used
+ -s Print all series from epg.data and exit
+ -v debuglevel Level of debug-messages to print
+ -h This Help-Page
+};
+
+ # Only process commandline if not already processed
+ if (!$Opts{done}) {
+ die $Usage if (!getopts("d:p:c:i:sv:h",\%Opts));
}
+ die $Usage if ($Opts{h});
+ # Mark the options as already processed
+ $Opts{done} = 1;
-sub init
- {
- &initconfigfile();
- &initsocket();
- &initmovie();
- &initblacklist();
- &initdone();
- &initchannellist();
- &initepgdata();
- &inittorecord();
+ if ($Opts{v}) {
+ $debug = $Opts{v};
+ }
+ if ($Opts{i}) {
+ $currentVDR = $Opts{i};
+ }
+ if ($Opts{d}) {
+ @Dest = ($Opts{d});
}
+ if ($Opts{c}) {
+ $configdir = $Opts{c};
+ }
+}
+
+sub init {
+ &initcommandline();
+ &initconfigfile();
+ # Process commandline a second time, so that configs from the config-file are overwritten
+ &initcommandline();
+ &initsocket();
+ &initmovie();
+ &initdone();
+ &initchannellist();
+ &inittorecord("deepblack");
+ &initepgdata();
+ &inittorecord("torecord");
+}
diff --git a/Tools/master-timer/sample/channels-to-scan b/Tools/master-timer/sample/channels-to-scan
index 6acf157..22f473d 100644
--- a/Tools/master-timer/sample/channels-to-scan
+++ b/Tools/master-timer/sample/channels-to-scan
@@ -3,6 +3,4 @@
3
4
5
-13
-18
-21
+49
diff --git a/Tools/master-timer/sample/config b/Tools/master-timer/sample/config
index d01c8a8..3180943 100644
--- a/Tools/master-timer/sample/config
+++ b/Tools/master-timer/sample/config
@@ -1,14 +1,32 @@
-# How Many Seconds "too early" should the timer begin
+# Master-Timer config file. Values shown here are defaults.
+
+# How many seconds "too early" should the timer begin
marginstart = 600
-# How Many Seocnds "too long" should the timer end
+
+# How many seconds "too long" should the timer end
marginstop = 600
-# When the Prio isn't provied in the config-File use this value
+
+# When the Prio isn't provided in the config file use this value
defaultprio = 50
-# How many DVB-Cards are installed in the Computer (Not used yet)
-DVBCards = 3
-# IP/Hostname:Port of the Destinations (Space is used for delimiter)
-Dest-Host = localhost:2001
-# Should Timers on the same channels be joined when they overlapp (0 = off)
-jointimers = 1
-# Debug-Level
+
+# How many DVB cards are installed in the computer (not used yet)
+DVBCards = 1
+
+# IP/Hostname:Port of the destination (space is used for delimiter)
+Dest = localhost:2001
+
+# Should timers on the same channels be joined when they overlap (0 = off)
+jointimers = 0
+
+# Should the description be transfered to VDR?
+description = 0
+
+# Debug level
+# 1 : Dump "torecord"
+# 2 : Dump all timers
+# 4 : Show when a timer will be deleted
+# 8 : Dump the "Done" REs
+# 16 : Verbose config reading
+# 32 : Dump program variables
+# 64 : Excessive deepblack/torecord debuging
debug = 0
diff --git a/Tools/master-timer/sample/convert-channel-list b/Tools/master-timer/sample/convert-channel-list
new file mode 100644
index 0000000..a97f3c5
--- /dev/null
+++ b/Tools/master-timer/sample/convert-channel-list
@@ -0,0 +1,26 @@
+Kabel 1|Kabel 1
+MTV|MTV Central
+PRW 13TH Street|13th Street
+PRW Discovery Channel|Discovery Channel
+PRW Disney Channel|Disney Channel
+PRW FOX KIDS|Fox Kids
+PRW Junior|Junior
+PRW K-Toon|K-Toon
+PRW Krimi & Co|Krimi &Co
+PRW Planet|Planet
+PRW Sci-Fantasy|Premiere Sci-Fi
+PRW Studio Universal|Studio Universal
+PRW Sunset|Sunset
+Premiere Action|Premiere Action
+Premiere Comedy|Premiere Comedy
+Premiere STAR|Premiere Star
+Premiere World 1|Premiere 1
+Premiere World 2|Premiere 2
+Premiere World 3|premiere 3
+Pro Sieben|Pro-7
+RTL|RTL
+RTL 2|RTL2
+Sat.1|Sat.1
+Super RTL|Super RTL
+Viva|VIVA
+Vox|VOX
diff --git a/Tools/master-timer/sample/deepblack b/Tools/master-timer/sample/deepblack
index 63b4f9e..12884fe 100644
--- a/Tools/master-timer/sample/deepblack
+++ b/Tools/master-timer/sample/deepblack
@@ -1,79 +1,172 @@
-Für alle Fälle Stefanie
-'MAX' - Das ganze Leben!
-10 vor 11
-17:30 live
-18:30
-24 Stunden
-Andreas Türck
-Arabella
-^BIZZ$
-Big Brother
-Britt - Der Talk um Eins
-Bärbel Schäfer
-Call TV
-Chicago Hope - Endstation Hoffnung
-Chicago Hope
-DIE REDAKTION
-Dauerwerbesendungen
-Die Harald Schmidt Show
-Die Oliver Geissen Show
-Die Quiz Show
-Doppelter Einsatz
-Dr. Stefan Frank - Der Arzt, dem die Frauen vertrauen
-EXCLUSIV
-EXTRA
-Ehekriege
-Ein Bayer auf Rügen
-Emergency Room
-Explosiv - Das Magazin
-GIRLSCAMP
-Glücksrad
-Gute Zeiten, schlechte Zeiten
-Hallo, Onkel Doc!
-Hans Meiser
-Hercules
-Hinter Gittern - Der Frauenknast
-Infomercials
-Jeder gegen Jeden
-K1 DIE REPORTAGE
-K1 Das Magazin
-K1 Nachrichten
-Kickers
-Kochduell
-Nachrichten
-Nicole - Entscheidung am Nachmittag
-OP ruft Dr. Bruckner
-PREMIERE WORLD - Das Programm
-PROSIEBEN REPORTAGE
-Peter Imhof
-Programm ab
-Programm von
-Punkt 12
-Punkt 6
-Punkt 9
-RTL II News
-RTL SHOP
-RTL aktuell
-RTL-Nachtjournal
-SAT.1-FRÜHSTÜCKSFERNSEHEN
-Spiegel TV-Reportage
-UEFA Champions
-fussball
-fßball
-Vera am Mittag
-Wolffs Revier
-Zapping
-alphateam
-peep!
-s.a.m.
-taff.
-^blitz$
-SK Kölsch
-^Becker$
-Kommissar Rex
-Fit For Fun TV
-Nur die Liebe zählt
-Unsere kleine Farm
-Die Waltons
-^Die Zwei$
-^Sieben$
+# [<Anytext>]
+# This marks the beginning of a deepblack-entry
+# Title = <text>
+# This matches a title
+# Subtitle = <text>
+# This matches a subtitle
+# Description = <text>
+# This matches a description
+# Category = <left>/<right>
+# This matches a DTV-Category
+# Channel = <Channel>
+# Restricts a deepblack-entry to a specific channel.
+# A single "!" at start of channel list negates the selection.
+# Timeframe = <begin>-<end>
+# Restricts a deepblack-entry to a specific timeframe.
+# No timers with start time in the timeframe will be programmed.
+# minlength = <Number>
+# Restricts a deepblack-entry to a specific minimum length
+# (postfix "m" for minutes, "h" for hours.)
+# maxlength = <Number>
+# Restricts a deepblack-entry to a specific maximum length
+# (postfix "m" for minutes, "h" for hours.)
+# weekday = MTWTFSS
+# Restricts a deepblack-entry to a specific weekday
+# instance = <Number>
+# Only apply this deepblack-entry for a specific Instance
+# "s" is a special value used for "-s"-Mode
+#
+# The "Title", "Subtitle", "Description", "Channel"-Lines can be
+# supplied any number of times for a specific entry
+#
+# To deepblack something at least one of the "Title", "Subtitle" or
+# "Description" (If you don't have anything "better" use "Title = ."
+# for this matches everything) fields has to be provided.
+# These three fields are "include" and the rest are "exclude" fields.
+
+[Blacklist all Talkshows]
+Title = .
+Category = Talk
+
+[Blacklist all Lifestyles]
+Title = .
+Category = /Lifestyles
+
+[Blacklist Sport/Tennis]
+Title = .
+Category = Sport/Tennis
+
+[Record only ZDF and Pro7]
+Title = .
+Channel = !ZDF
+Channel = ProSieben
+
+[Blacklist a timeframe]
+Title = .
+Timeframe = 1000-1400
+
+[Blacklist everything with less than 5 minutes duration]
+Title = .
+maxlength = 5m
+
+[Sinnlose Serien]
+Title = Für alle Fälle Stefanie
+Title = Chicago Hope - Endstation Hoffnung
+Title = Chicago Hope
+Title = Doppelter Einsatz
+Title = Dr. Stefan Frank - Der Arzt, dem die Frauen vertrauen
+Title = Ehekriege
+Title = Ein Bayer auf Rügen
+Title = Emergency Room
+Title = Gute Zeiten, schlechte Zeiten
+Title = Hallo, Onkel Doc!
+Title = Hercules
+Title = Hinter Gittern - Der Frauenknast
+Title = OP ruft Dr. Bruckner
+Title = Wolffs Revier
+Title = alphateam
+Title = SK Kölsch
+Title = ^Becker$
+Title = Kommissar Rex
+Title = Nur die Liebe zählt
+Title = Unsere kleine Farm
+Title = Die Waltons
+Title = ^Die Zwei$
+
+[Glueckspiele]
+Title = Die Quiz Show
+Title = Glücksrad
+Title = Jeder gegen Jeden
+Title = Kochduell
+
+[Infotainment und Boulevardzeug]
+Title = 'MAX' - Das ganze Leben!
+Title = ^BIZZ$
+Title = Big Brother
+Title = GIRLSCAMP
+Title = Call TV
+Title = DIE REDAKTION
+Title = EXCLUSIV
+Title = EXTRA
+Title = Explosiv - Das Magazin
+Title = K1 DIE REPORTAGE
+Title = K1 Das Magazin
+Title = PROSIEBEN REPORTAGE
+Title = Fit For Fun TV
+Title = peep!
+Title = s.a.m.
+Title = taff.
+Title = ^blitz$
+Title = Die Harald Schmidt Show
+Title = Spiegel TV-Reportage
+
+[Nachrichten]
+Title = 10 vor 11
+Title = 17:30 live
+Title = 18:30
+Title = 24 Stunden
+Title = Punkt 12
+Title = Punkt 6
+Title = Punkt 9
+Title = RTL II News
+Title = RTL aktuell
+Title = RTL-Nachtjournal
+Title = K1 Nachrichten
+Title = Nachrichten
+
+[Talkshows]
+Title = Andreas Türck
+Title = Arabella
+Title = Britt - Der Talk um Eins
+Title = Bärbel Schäfer
+Title = Die Oliver Geissen Show
+Title = Peter Imhof
+Title = Vera am Mittag
+Title = Hans Meiser
+Title = Nicole - Entscheidung am Nachmittag
+Title = Franklin
+
+[So richtig Sinnloses]
+Title = Dauerwerbesendungen
+Title = Infomercials
+Title = Kickers
+Title = RTL SHOP
+Title = SAT.1-FRÜHSTÜCKSFERNSEHEN
+Title = Zapping
+
+[PREMIERE WORLD - Das Programm]
+Title = PREMIERE WORLD - Das Programm
+Title = Programm ab
+Title = Programm von
+
+[Fussball]
+Title = fussball
+Title = fußball
+Title = UEFA Champions
+
+#Sonstiges
+[^Sieben$]
+Title = ^Sieben$
+
+[Starporträt Kevin Spacey]
+Title = Starporträt Kevin Spacey
+
+
+[All Movies for -s]
+Subtitle = MOVIE
+Instance = s
+
+[All >= 65m for -s]
+Title = .
+minlength = 65m
+Instance = s
diff --git a/Tools/master-timer/sample/subtitle-movie b/Tools/master-timer/sample/subtitle-movie
index 3b5a0ab..9bd3579 100644
--- a/Tools/master-timer/sample/subtitle-movie
+++ b/Tools/master-timer/sample/subtitle-movie
@@ -3,6 +3,7 @@
^Actionkomödie$
^Actionthriller$
^Agentenfilm$
+^Beziehungskomödie$
^Biografie$
^Biographie$
^Computeranimation$
@@ -12,19 +13,24 @@
^Familiendrama$
^Fantasy$
^Fantasykomödie$
+^Fantasy-Komödie$
^Gangsterfilm$
^Gerichtsfilm$
^Gesellschaftsdrama$
+^Historiendrama$
^Horrorfilm$
^Horrorkomödie$
+^Jugenddrama$
^Kinderfilm$
^Komödie$
^Kriegsfilm$
^Krimikomödie$
^Kriminalfilm$
^Liebesfilm$
+^Liebeskomödie$
^Melodram$
^Melodrama$
+^Monumentalfilm$
^Musical$
^Politthriller$
^Psychothriller$
@@ -32,10 +38,15 @@
^Romanze$
^Satire$
^Science-Fiction$
+^Science-Fiction-Komödie$
^Spielfilm$
^TV Movie$
^TV-Drama$
+^Teil .$
+^Teil 0.$
^Thriller$
+^Tragikomödie$
^Western$
+^Westernkomödie$
^Zeichentrick$
^Zeichentrickkomödie$
diff --git a/Tools/master-timer/sample/torecord b/Tools/master-timer/sample/torecord
index 0306830..0c97b91 100644
--- a/Tools/master-timer/sample/torecord
+++ b/Tools/master-timer/sample/torecord
@@ -1,32 +1,90 @@
-# Format: (Every field is "optional".
-# [Title RE|Subtitle RE|Description RE|Channel-Name|Timeframe|Prio|Timer-Title|Marginstart;Marginstop|VDR-Instance]
+# [<Anytext>]
+# This marks the beginning of a timer entry
+# Title = <text>
+# This matches a title
+# Subtitle = <text>
+# This matches a subtitle.
+# You may use the magic "MOVIE" or "!MOVIE" which matches
+# all entries from file "subtitle-movie".
+# Description = <text>
+# This matches a description
+# Category = <left>/<right>
+# This matches a DTV-Category
+# Channel = <Channel>
+# Restricts a time to a specific channel.
+# A single "!" at start of channel list negates the selection.
+# Timeframe = <begin>-<end>
+# Restricts timer to a specific timeframe.
+# Only timers with start time in the timeframe will be programmed.
+# minlength = <Number>
+# Restricts timer entry to a specific minimum length
+# (postfix "m" for minutes, "h" for hours.)
+# maxlength = <Number>
+# Restricts a timer entry to a specific maximum length
+# (postfix "m" for minutes, "h" for hours.)
+# weekday = MTWTFSS
+# Restricts a timer to a specific weekday
+# Timertitle = <text>
+# The title used for this timer.
+# If this is not provided "Title" will be used.
+# If "Title" is not provided the EPG title will be used.
+# Margin = <Number>;<Number>
+# Seconds added to the beginning and end of the timer.
+# Positive numbers will lengthen the recording.
+# instance = <Number>
+# The instance of VDR for which this timer is.
+# If this is not provided the timer is valid for ALL instances.
#
-# To record something at least one of the "Title", "Subtitle" or "Description"
-# Fields has to be provided. This 3 fields are "include" and the rest are
-# "exclude" fields!
-#
-# More than one channel definition can be provided. The delimiter is ";"
-# Additionaly you can make a "blacklist" of Channels when you prepent a "!" to the first Channel Definition
-# The "!" is only tested for the FIRST Channel definition.
-# You can only have a white or a blacklist (Mixing doesn't make sense!)
-#
-# ex. Record the series "Deep Space Nine" on Sci-Fantasy in the timeframe 09:00 - 14:00 with 60 Seconds Marginstart and -60 Seconds Marginstop
-# Deep Space Nine|||Sci-Fantasy|0900-1400|99|DS9|60;-60
+# The "Title", "Subtitle", "Description", "Channel"-Lines can be
+# supplied any number of times for a specific entry
#
-# Record all "Actionfilm"s with "Schwarzenegger"
-# |Actionfilm|Schwarzenegger
-#
-Babylon 5|||!Pro-7||99|60;-60|1
-Deep Space Nine|||||99|DS9|60;-60|2
-Seven Days|||||99|
-Stargate|||||99|
-Futurama||||2100-2300|50|
-Ally McBeal|||||99|
-Snoops|||||50|
-^Friends$|||||99|Friends|
-Pensacola|||||50|
-seaQuest|||||50|
-||Paltrow|Sci Fantasy;13th Street;Star Kino;Cine Action;Cine Comedy;Romantic Movies;Studio Universal;Premiere||99|
-||Aniston|||99|
-Matrix
+# To record something at least one of the "Title", "Subtitle" or "Description"
+# fields has to be provided. These three fields are "include" and the rest are
+# "exclude" fields!
+
+[Dies ist ein Test-Timer]
+Title = Titel
+Subtitle = Subtitel
+Description = Description
+Category = Serie/Krimi
+Channel = Pro-7
+Channel = VIVA
+Timeframe = 1230-1830
+Prio = 50
+Lifetime = 50
+minlength = 10m
+maxlength = 3h
+weekday = ---T---
+Timertitle = Test
+Margin = 600;600
+instance = 2
+
+# Record Babylon 5 only if NOT playing on Pro 7;
+# recording starts one minute too early and ends
+# one minute too early (to skip following ads).
+[Babylon 5]
+Title = Babylon 5
+Channel = !Pro-7
+Prio = 99
+Margin = 60;-60
+
+[DS9]
+Title = Deep Space Nine
+Prio = 99
+Timertitle = DS9
+Margin = 60;-60
+
+[Seven Days]
+Title = Seven Days
+Prio = 99
+
+[Stargate]
+Title = Stargate
+Prio = 99
+
+[Aniston]
+Description = Aniston
+Prio = 99
+[Matrix]
+Title = Matrix