summaryrefslogtreecommitdiff
path: root/Tools
diff options
context:
space:
mode:
authorKlaus Schmidinger <kls (at) cadsoft (dot) de>2001-09-16 18:00:00 +0200
committerKlaus Schmidinger <kls (at) cadsoft (dot) de>2001-09-16 18:00:00 +0200
commit156831036e9b0fcbfc719033cc89e08c1985cad6 (patch)
treedede3254f8982f36fe40a11f7ce333b13f2297d6 /Tools
parentbb18b9e0b449afff418f010c1b2e255acd3fbad3 (diff)
downloadvdr-patch-lnbsharing-156831036e9b0fcbfc719033cc89e08c1985cad6.tar.gz
vdr-patch-lnbsharing-156831036e9b0fcbfc719033cc89e08c1985cad6.tar.bz2
Version 0.95vdr-0.95
- Fixed behaviour in case the shutdown didn't take place (there were many "next timer event at..." messages in that case). - Reduced the default value for MinEventTimeout to 30 minutes. - Fixed detecting manual start in shutdown feature. - An error message is now displayed in case the Transfer Mode can't be started because the necessary DVB card is currently recording (or there is no DVB card that can access this channel). - Fixed toggling channels with the '0' key in case the "Ok" button has been pressed to display the current/next information. - Pressing the "Power" key now always initiates the shutdown sequence (after user confirmation in case of a recording timer), event if there is currently a menu or a replay session active. Note the additional remarks in INSTALL regarding the values of the two parameters given to the shutdown program in case of a currently recording timer. - Switching through channel groups with the "Left" and "Right" keys now always starts at the group that contains the current channel. - Implemented "Multi Speed Mode" (thanks to Stefan Huelswitt). - Implemented backtracing to hit the right spot after fast forward/rewind (thanks to Stefan Huelswitt). - Implemented replay mode display (thanks to Stefan Huelswitt, with a few rewrites by kls). - Changed the size of all input buffers used to parse config files or receive SVDRP commands to the same value of 10KB. This allows long strings to be used in the 'summary' field of a timer, for instance. - The pipe to the Dolby Digital replay command (option '-a') now closes all unused file descriptors in the child process to avoid crashing when the OSD is used (thanks to Andreas Vitting). - Switched to the driver's new tuning API (VDR now requires a driver version dated 2001-09-14 or higher). - Changed obsolete macro VIDEO_WINDOW_CHROMAKEY to VID_TYPE_CHROMAKEY (thanks to Guido Fiala). - New version of the "Master-Timer" tool (thanks to Matthias Schniedermeyer). - Better error handling when writing configuration files. - Fixed putting the final editing mark into the edited version's marks file. - Fixed manipulating an editing mark at the very end of a recording. - Fixed starting a new replay immediately after stopping a previous one (had caused a mix between live video and replay). - Three new keys ("Volume+", Volume-" and "Mute") to control the DVB card's audio output volume. - New version of the 'epg2timers' tool (thanks to Carsten Koch).
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