summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CONTRIBUTORS55
-rw-r--r--HISTORY66
-rw-r--r--MANUAL21
-rw-r--r--Makefile28
-rw-r--r--PLUGINS.html620
-rw-r--r--PLUGINS/SRC/hello/COPYING340
-rw-r--r--PLUGINS/SRC/hello/HISTORY6
-rw-r--r--PLUGINS/SRC/hello/Makefile78
-rw-r--r--PLUGINS/SRC/hello/README11
-rw-r--r--PLUGINS/SRC/hello/hello.c105
-rw-r--r--PLUGINS/SRC/hello/i18n.c52
-rw-r--r--PLUGINS/SRC/hello/i18n.h11
-rw-r--r--channels.conf125
-rw-r--r--channels.conf.cable291
-rw-r--r--channels.conf.terr9
-rw-r--r--config.c377
-rw-r--r--config.h43
-rw-r--r--dvbapi.c33
-rw-r--r--dvbapi.h4
-rw-r--r--dvbosd.c5
-rw-r--r--i18n.c414
-rw-r--r--i18n.h20
-rw-r--r--interface.h3
-rw-r--r--menu.c611
-rw-r--r--menu.h8
-rw-r--r--menuitems.c476
-rw-r--r--menuitems.h110
-rwxr-xr-xnewplugin250
-rw-r--r--osd.c11
-rw-r--r--osd.h4
-rw-r--r--plugin.c319
-rw-r--r--plugin.h81
-rw-r--r--recording.c6
-rw-r--r--remote.h4
-rw-r--r--ringbuffer.c66
-rw-r--r--tools.c8
-rw-r--r--vdr.124
-rw-r--r--vdr.c133
38 files changed, 3797 insertions, 1031 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index ec742b1..b6bd60a 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -1,4 +1,7 @@
-Thanks go to the following people for patches and contributions:
+Tons of suggestions, bugreports, patches and other contributions have been
+provided by the people on the 'linux-dvb' and 'vdr' mailing lists.
+Special thanks go to the following individuals (if your name is missing here,
+please send an email to kls@cadsoft.de):
Carsten Koch <Carsten.Koch@icem.de>
for adding LIRC support
@@ -9,6 +12,7 @@ Carsten Koch <Carsten.Koch@icem.de>
for implementing the 'new recording' indicator
for suggesting that the "Back" button in replay mode should bring up the "Recordings" menu
for fixing the watchdog timer if the program hangs in OSD activities
+ for his support in keeping the Premiere World channels up to date in 'channels.conf'
Plamen Ganev <pganev@com-it.net>
for fixing the frequency offset for Hotbird channels
@@ -28,7 +32,7 @@ Guido Fiala <gfiala@s.netic.de>
now does these things itself)
for making the replay progress display avoid unnecessary code execution
-Robert Schneider <Robert.Schneider@lotus.com>
+Robert Schneider <Robert.Schneider@de.ibm.com>
for implementing EIT support for displaying the current/next info
for extending EIT support to implement a complete EPG
@@ -117,6 +121,13 @@ Stefan Huelswitt <huels@iname.com>
for implementing backtracing for fast forward/rewind
for implementing the replay mode display
for fixing a crash when replaying with DEBUG_OSD=1
+ for fixing a crash when selecting the "Jump" function directly after setting
+ an editing mark
+ for reporting a possible endless loop in shifting recordings between DVB cards
+ for making it no longer setting PIDs 0x1FFF, which apparently fixes problems
+ with CAMs and AC3 sound only working the first time
+ for making the main loop take an active video cutting process into account when
+ doing shutdown or housekeeping
Ulrich Röder <roeder@efr-net.de>
for pointing out that there are channels that have a symbol rate higher than
@@ -157,6 +168,8 @@ Werner Fink <werner@suse.de>
for helping to debug leftover 'zombie' processes when closing a pipe
for making the Dolby Digital thread start only if the recording actually
contains Dolby Digital data
+ for improving thread locking in the ring buffer to avoid possible race conditions
+ under heavy load
Rolf Hakenes <hakenes@hippomi.de>
for providing 'libdtv' and adapting the EIT mechanisms to it
@@ -185,7 +198,7 @@ Thomas Heiligenmann <thomas@heiligenmann.de>
Norbert Schmidt <nschmidt-nrw@t-online.de>
for filling in some missing teletext PIDs
-Thilo Wunderlich <tw@ubcom.net>
+Thilo Wunderlich <wunderlich@speedway.org>
for his help in keeping 'channels.conf' up to date
for reporting a problem with accessing the epg.data file before it is fully written
@@ -202,6 +215,8 @@ Sergei Haller <Sergei.Haller@math.uni-giessen.de>
for adding the TPID to Hessen-3 in 'channels.conf'
for suggesting that the EPG scan should skip channels with their 'Ca' parameter
explicitly set to an other DVB card
+ for implementing enhanced string editing with upper-/lowercase, insert/overwrite
+ and delete
Andreas Gebel <andreas@xcapenet.de>
for his help in keeping 'channels.conf' up to date
@@ -280,3 +295,37 @@ Dirk Wiebel <dirk@wiebel.de>
Gerald Raaf <graaf@attglobal.net>
for helping to fix the still picture workaround in case the progress display
is active
+ for his support in keeping the Premiere World channels up to date in 'channels.conf'
+
+Andreas Roedl <flood@flood-net.de>
+ for adding some DVB-T channels for Berlin (Germany) to channels.conf.terr
+
+Jean Martin <mac_j_fr@hotmail.com>
+ for pointing out a problem with OSD color palette handling on "big endian" systems
+
+Steffen Koch <Steffen.Koch@koch-enterprises.de>
+ for reporting a crash when selecting the "Jump" function directly after setting
+ an editing mark
+
+Matthias Hilbig <hilbig@upb.de>
+ for fixing some missing ',' in i18n.c
+
+Simon Dean <linux-dvb@sickhack.com>
+ for reporting a problem with '.' at the end of a directory name in case of VFAT=1
+ (Windows can't handle these)
+
+Dimitrios Dimitrakos <mail@dimitrios.de>
+ for translating OSD texts to the Greek language
+
+Marcus Kuba <marcus@kuba4u.de>
+ for reporting a bug in the unit of the "SVDRP timeout" setup parameter
+
+Ulrich Petri <ulope@gmx.de>
+ for his help in debugging a crash on systems with disks that have a block size
+ larger than 1MB
+
+Oliver Lorei <oliverlorei@cityweb.de>
+ for his support in keeping the Premiere World channels up to date in 'channels.conf.cable'
+
+Andreas Böttger <fboettger@t-online.de>
+ for reporting a bug in skipping forward in time shift mode near the end of the recording
diff --git a/HISTORY b/HISTORY
index af15667..6599534 100644
--- a/HISTORY
+++ b/HISTORY
@@ -1,7 +1,9 @@
Video Disk Recorder Revision History
------------------------------------
-2000-02-19: Version 0.01 (Initial revision).
+2000-02-19: Version 0.01
+
+- Initial revision.
2000-03-11: Version 0.02
@@ -1190,3 +1192,65 @@ Video Disk Recorder Revision History
- Fixed a bug in the editing process in case a previously edited file with the
same name was manually deleted on a system with more than one video directory
(thanks to Dirk Wiebel for reporting this one).
+
+2002-04-21: Version 1.0.1
+
+- Added some DVB-T channels for Berlin (Germany) to channels.conf.terr (thanks to
+ Andreas Roedl).
+- Implemented enhanced string editing with upper-/lowercase, insert/overwrite
+ and delete (thanks to Sergei Haller).
+- Fixed color palette handling on "big endian" systems (thanks to Jean Martin
+ for pointing out this one).
+- Updated the "Blue Movie" channels to the new "Premiere Erotik" (thanks to
+ Thilo Wunderlich). NOTE: this adds a new channel to 'channels.conf', so that
+ any timers referencing a channel with a number higher than 102 should be
+ checked and adapted if necessary (this only applies if you are using the default
+ 'channels.conf').
+- Improved thread locking in the ring buffer to avoid possible race conditions
+ under heavy load (thanks to Werner Fink).
+- Fixed a crash when selecting the "Jump" function directly after setting an
+ editing mark (thanks to Steffen Koch for reporting and Stefan Huelswitt for
+ fixing this one).
+- Fixed some missing ',' in i18n.c (thanks to Matthias Hilbig).
+- Fixed a possible endless loop in shifting recordings between DVB cards (thanks
+ to Stefan Huelswitt for reporting this one).
+- Updated the Premiere World Formula 1 channels in 'channels.conf' (thanks to Mel
+ Schächner).
+- No longer setting PIDs 0x1FFF, which apparently fixes problems with CAMs and
+ AC3 sound only working the first time (thanks to Stefan Huelswitt).
+- Now encoding '.' at the end of a directory name in case of VFAT=1, since Windows
+ can't handle these (thanks to Simon Dean for reporting this one).
+
+2002-05-05: Version 1.0.2
+
+- Now taking an active video cutting process into account when doing shutdown or
+ housekeeping (thanks to Stefan Huelswitt).
+- The default duration of an instant recording has been increased to 3 hours and
+ is now configurable in the "Setup/Recording" menu.
+- Added Greek language texts (thanks to Dimitrios Dimitrakos).
+- Fixed the unit of the "SVDRP timeout" setup parameter (thanks to Marcus Kuba
+ for reporting this one).
+- Fixed a crash on systems with disks that have a block size larger than 1MB
+ (thanks to Ulrich Petri for helping to debug this one).
+- Updated 'channels.conf' for the new PW settings (thanks to Andreas Share,
+ Carsten Koch, Gerald Raaf and Mel Schächner). Note that all channels with numbers
+ over 50 may have moved, so you should carefully check any timers you have set!
+- Updated 'channels.conf.cable' for the new PW settings (thanks to Oliver Lorei
+ Stephan Schreiber and Uwe Scheffler). Note that all channels may have moved, so
+ you should carefully check any timers you have set!
+ For future updates of this file somebody with digital cable should take the role
+ of the "maintainer" and send me updated versions based on the file that comes
+ with the most recent version of VDR. I will then simply replace the entire file
+ 'channels.conf.cable' whenever a new version is sent to me.
+- Fixed skipping forward in time shift mode near the end of the recording (thanks
+ to Andreas Böttger for reporting this one).
+
+2002-05-09: Version 1.1.0
+
+- Begin of the 1.1 development branch. THIS IS NOT A STABLE VERSION!
+ The current stable version for every day use is still the 1.0 branch.
+- First step towards a universal plugin interface. See the file PLUGINS.html
+ for a detailed description. The man page vdr(1) describes the new options '-L'
+ and '-P' used to load plugins. This first step implements the complete "outer"
+ shell for plugins. The "inner" access to VDR data structures will follow.
+- The VDR version number is now displayed in the title line of the "Setup" menu.
diff --git a/MANUAL b/MANUAL
index b940505..9787131 100644
--- a/MANUAL
+++ b/MANUAL
@@ -17,9 +17,9 @@ Video Disk Recorder User's Manual
Ok Ch display Select Switch Edit Accept Play Progress disp.
Menu Menu on Menu off Menu off Menu off Menu off Menu off Menu on
Back - Menu off VDR menu VDR menu Discard VDR menu Recordings menu
- Red - Record Edit Edit - Play Jump
- Green - Language New New - Rewind Skip -60s
- Yellow - - Delete Delete - Delete Skip +60s
+ Red - Record Edit Edit ABC/abc Play Jump
+ Green - Language New New Ins/Ovr Rewind Skip -60s
+ Yellow - - Delete Delete Delete Delete Skip +60s
Blue - Stop/Resume Mark On/Off(1) - Summary Stop
0..9 Ch select - - - Numeric inp. - Editing
@@ -58,11 +58,10 @@ Video Disk Recorder User's Manual
by pressing the "Right" button (which puts brackets around the current
character as in "[R]TL"), selecting the desired character position with
"Left" and "Right", and changing the character with the "Up" and "Down"
- keys. "Ok" then confirms the changes. The special character '^' can be used
- to "cut off" a string at this position. When this character is visible in the
- brackets (as in abc[^]), the next press to the "Left" or "Ok" button will
- actually cut off the string. Using "Up" and/or "Down" brings back the
- original rest of the string (unless you have pressed "Left" or "Ok").
+ keys. "Ok" then confirms the changes. The "Red" key toggles between
+ upper- and lowercase characters, while the "Green" key switches between
+ insert and overwrite mode. The "Yellow" key deletes the current character
+ (or the one to the right of the cursor in insert mode).
The "Red", "Green", "Yellow" and "Blue" buttons have special meanings
in various menus and are listed at the bottom of the on-screen-display.
@@ -519,6 +518,12 @@ Video Disk Recorder User's Manual
If this parameter is empty, the channel name will be used
by default.
+ Instant rec. time = 180
+ Defines the duration of an instant recording in minutes.
+ Default is 180 minutes (3 hours). The stop time of an
+ instant recording can be modified at any time by editing
+ the respective timer in the "Timers" menu.
+
Record Dolby Digital = yes
Turns recording of the Dolby Digital audio channels on
or off. This may be useful if you don't have the equipment
diff --git a/Makefile b/Makefile
index 62fd897..55a01e8 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@
# See the main source file 'vdr.c' for copyright information and
# how to reach the author.
#
-# $Id: Makefile 1.33 2002/04/01 12:50:48 kls Exp $
+# $Id: Makefile 1.34 2002/05/09 09:35:05 kls Exp $
.DELETE_ON_ERROR:
@@ -13,15 +13,17 @@ DTVDIR = ./libdtv
MANDIR = /usr/local/man
BINDIR = /usr/local/bin
+PLUGINDIR= ./PLUGINS
+
VIDEODIR = /video
INCLUDES = -I$(DVBDIR)/ost/include
DTVLIB = $(DTVDIR)/libdtv.a
-OBJS = config.o dvbapi.o dvbosd.o eit.o font.o i18n.o interface.o menu.o osd.o\
- recording.o remote.o remux.o ringbuffer.o svdrp.o thread.o tools.o vdr.o\
- videodir.o
+OBJS = config.o dvbapi.o dvbosd.o eit.o font.o i18n.o interface.o menu.o\
+ menuitems.o osd.o plugin.o recording.o remote.o remux.o ringbuffer.o\
+ svdrp.o thread.o tools.o vdr.o videodir.o
OSDFONT = -adobe-helvetica-medium-r-normal--23-*-100-100-p-*-iso8859-1
FIXFONT = -adobe-courier-bold-r-normal--25-*-100-100-m-*-iso8859-1
@@ -69,7 +71,7 @@ include $(DEPFILE)
# The main program:
vdr: $(OBJS) $(DTVLIB)
- g++ -g -O2 $(OBJS) $(NCURSESLIB) -ljpeg -lpthread $(LIBDIRS) $(DTVLIB) -o vdr
+ g++ -g -O2 -rdynamic $(OBJS) $(NCURSESLIB) -ljpeg -lpthread -ldl $(LIBDIRS) $(DTVLIB) -o vdr
# The font files:
@@ -88,6 +90,21 @@ genfontfile: genfontfile.c
$(DTVLIB) $(DTVDIR)/libdtv.h:
make -C $(DTVDIR) all
+# The 'include' directory (for plugins):
+
+include-dir:
+ @mkdir -p include/vdr
+ @(cd include/vdr; for i in ../../*.h; do ln -fs $$i .; done)
+
+# Plugins:
+
+plugins: include-dir
+ @for i in `ls $(PLUGINDIR)/SRC | grep -v '[^a-z0-9]'`; do make -C "$(PLUGINDIR)/SRC/$$i" all; done
+
+plugins-clean:
+ @for i in `ls $(PLUGINDIR)/SRC | grep -v '[^a-z0-9]'`; do make -C "$(PLUGINDIR)/SRC/$$i" clean; done
+ @-rm -f $(PLUGINDIR)/lib/*
+
# Install the files:
install:
@@ -104,6 +121,7 @@ install:
clean:
make -C $(DTVDIR) clean
-rm -f $(OBJS) $(DEPFILE) vdr genfontfile genfontfile.o core* *~
+ -rm -rf include
fontclean:
-rm -f fontfix.c fontosd.c
CLEAN: clean fontclean
diff --git a/PLUGINS.html b/PLUGINS.html
new file mode 100644
index 0000000..b903f04
--- /dev/null
+++ b/PLUGINS.html
@@ -0,0 +1,620 @@
+<html>
+<head>
+<title>The VDR Plugin System</title>
+</head>
+<body bgcolor="white">
+
+<h1>The VDR Plugin System</h1>
+
+VDR provides an easy to use plugin interface that allows additional functionality
+to be added to the program by implementing a dynamically loadable library file.
+This interface allows programmers to develop additional functionality for VDR completely
+separate from the core VDR source, without the need of patching the original
+VDR code (and all the problems of correlating various patches).
+<p>
+This document describes the "outside" interface of the plugin system.
+It handles everything necessary for a plugin to get hooked into the core
+VDR program and present itself to the user.
+
+<!--<p>TODO: Link to the document about VDR base classes to use when implementing actual functionality (yet to be written).-->
+
+<hr><h2>Quick start</h2>
+
+<center><i><b>Can't wait, can't wait!</b></i></center><p>
+
+Actually you should read this entire document before starting to work with VDR plugins,
+but you probably want to see something happening right away <tt>;-)</tt>
+<p>
+So, for a quick demonstration of the plugin system, there is a demo plugin called
+"hello" that comes with the VDR source. To test drive this one, do the following:
+<ul>
+<li>change into the VDR source directory
+<li><b><tt>make</tt></b> the VDR program with your usual <tt>REMOTE=...</tt> (and maybe other) options
+<li>do <b><tt>make plugins</tt></b> to build the demo plugin
+<li>run VDR with <b><tt>vdr -V</tt></b> to see the version information
+<li>run VDR with <b><tt>vdr -h</tt></b> to see the command line options
+<li>run VDR with <b><tt>vdr -Phello</tt></b>
+<li>open VDR's main menu and select the <i>Hello</i> item
+<li>open the <i>Setup</i> menu from VDR's main menu and select <i>Plugins</i>
+</ul>
+If you enjoyed this brief glimpse into VDR plugin handling, read through the rest of
+this document and eventually write your own VDR plugin.
+
+<hr><h2>The name of the plugin</h2>
+
+<center><i><b>Give me some I.D.!</b></i></center><p>
+
+One of the first things to consider when writing a VDR plugin is giving the thing
+a proper name. This name will be used in the VDR command line in order to load
+the plugin, and will also be the name of the plugin's source directory, as well
+as part of the final library name.
+<p>
+The plugin's name should typically be as short as possible. Three letter
+abbreviations like <b><tt>dvd</tt></b> (for a DVD player) or <b><tt>mp3</tt></b>
+(for an MP3 player) would be good choices. It is also recommended that the name
+consists of only lowercase letters and digits.
+No other characters should be used here.
+<p>
+A plugin can access its name through the (non virtual) member function
+
+<p><table><tr><td bgcolor=#F0F0F0><pre><br>
+const char *Name(void);
+</pre></td></tr></table><p>
+
+The actual name is derived from the plugin's library file name, as defined in the
+next chapter.
+
+<a name="The plugin directory structure"><hr><h2>The plugin directory structure</h2>
+
+<center><i><b>Where is everybody?</b></i></center><p>
+
+By default plugins are located in a directory named <tt>PLUGINS</tt> below the
+VDR source directory. Inside this directory the following subdirectory structure
+is used:
+
+<p><table><tr><td bgcolor=#F0F0F0><pre><br>
+VDR/PLUGINS/SRC
+VDR/PLUGINS/SRC/demo
+VDR/PLUGINS/SRC/hello
+VDR/PLUGINS/lib
+VDR/PLUGINS/lib/libvdr-demo.so.1.1.0
+VDR/PLUGINS/lib/libvdr-hello.so.1.1.0
+</pre></td></tr></table><p>
+
+The <tt>SRC</tt> directory contains one subdirectory for each plugin, which carries
+the name of that plugin (in the above example that would be <tt>demo</tt> and
+<tt>hello</tt>, respectively). What's inside the individual source directory of a
+plugin is entirely up to the author of that plugin. The only prerequisites are
+that there is a <tt>Makefile</tt> that provides the targets <tt>all</tt> and
+<tt>clean</tt>, and that a call to <tt>make all</tt> actually produces a dynamically
+loadable library file for that plugin (we'll get to the details later).
+<p>
+The <tt>lib</tt> directory contains the dynamically loadable libraries of all
+available plugins. Note that the names of these files are created by concatenating
+<p>
+<table border=2>
+<tr><td align=center><b><tt>libvdr-</tt></b></td><td align=center><b><tt>demo</tt></b></td><td align=center><b><tt>.so.</tt></b></td><td align=center><b><tt>1.1.0</tt></b></td></tr>
+<tr><td align=center><font size=-1>VDR plugin<br>library prefix</font></td><td align=center><font size=-1>name of<br>the plugin</font></td><td align=center><font size=-1>shared object<br>indicator</font></td><td align=center><font size=-1>VDR version number<br>this plugin was<br>compiled for</font></td></tr>
+</table>
+<p>
+The plugin library files can be stored in any directory. If the default organization
+is not used, the path to the plugin directory has be be given to VDR through the
+<b><tt>-L</tt></b> option.
+<p>
+The VDR <tt>Makefile</tt> contains the target <tt>plugins</tt>, which calls
+<tt>make all</tt> in every directory found under <tt>VDR/PLUGINS/SRC</tt>,
+plus the target <tt>plugins-clean</tt>, which calls <tt>make clean</tt> in
+each of these directories.
+<p>
+If you download a plugin <a href="#Building the distribution package">package</a>
+from the web, it will typically have a name like
+<p>
+<tt>vdr-demo-0.0.1.tgz</tt>
+<p>
+and will unpack into a directory named
+<p>
+<tt>vdr-demo-0.0.1</tt>
+<p>
+To use the <tt>plugins</tt> and <tt>plugins-clean</tt> targets from the VDR <tt>Makefile</tt>
+you need to unpack such an archive into the <tt>VDR/PLUGINS/SRC</tt> directory and
+create a symbolic link with the basic plugin name, as in
+
+<p><table><tr><td bgcolor=#F0F0F0><pre><br>
+ln -s vdr-demo-0.0.1 demo
+</pre></td></tr></table><p>
+
+Since the VDR <tt>Makefile</tt> only searches for directories with names consisting
+of only lowercase characters and digits, it will only follow the symbolic links, which
+should lead to the current version of the plugin you want to use. This way you can
+have several different versions of a plugin source (like <tt>vdr-demo-0.0.1</tt> and
+<tt>vdr-demo-0.0.2</tt>) and define which one to actually use through the symbolic link.
+
+<a name="Initializing a new plugin directory"><hr><h2>Initializing a new plugin directory</h2>
+
+<center><i><b>A room with a view</b></i></center><p>
+
+Call the Perl script <tt>newplugin</tt> from the VDR source directory to create
+a new plugin directory with a <tt>Makefile</tt> and a main source file implementing
+the basic derived plugin class.
+You will also find a <tt>README</tt> file there with some inital text, where you
+should fill in actual information about your project.
+A <tt>HISTORY</tt> file is set up with an "Initial revision" entry. As your project
+evolves, you should add the changes here with date and version number.
+<p>
+<tt>newplugin</tt> also creates a copy of the GPL license file <tt>COPYING</tt>,
+assuming that you will release your work under that license. Change this if you
+have other plans.
+<p>
+Add further files and maybe subdirectories to your plugin source directory as
+necessary. Don't forget to adapt the <tt>Makefile</tt> appropriately.
+
+<hr><h2>The actual implementation</h2>
+
+<center><i><b>Use the source, Luke!</b></i></center><p>
+
+A newly initialized plugin doesn't really do very much yet.
+If you <a href="#Loading plugins into VDR">load it into VDR</a> you will find a new
+entry in the main menu, with the same name as your plugin (where the first character
+has been converted to uppercase). There will also be a new entry named "Plugins" in
+the "Setup" menu, which will bring up a list of all loaded plugins, through which you
+can access each plugin's own setup parameters (if it provides any).
+<p>
+To implement actual functionality into your plugin you need to edit the source file
+that was generated as <tt>PLUGINS/SRC/name.c</tt>. Read the comments in that file
+to see where you can bring in your own code. The following sections of this document
+will walk you through the individual member functions of the plugin class.
+<p>
+Depending on what your plugin shall do, you may or may not need all of the given
+member functions. Except for the <tt>MainMenuEntry()</tt> function they all by default
+return values that will result in no actual functionality. You can either completely
+delete unused functions from your source file, or just leave them as they are.
+If your plugin shall not be accessible through VDR's main menu, simply remove
+(or comment out) the line implementing the <tt>MainMenuEntry()</tt> function.
+<p>
+At the end of the plugin's source file you will find a line that looks like this:
+
+<p><table><tr><td bgcolor=#F0F0F0><pre><br>
+VDRPLUGINCREATOR(cPluginDemo);
+</pre></td></tr></table><p>
+
+This is the "magic" hook that allows VDR to actually load the plugin into
+its memory. You don't need to worry about the details behind all this.
+<p>
+If your plugin requires additional source files, simply add them to your plugin's
+source directory and adjust the <tt>Makefile</tt> accordingly.
+
+<hr><h2>Construction and Destruction</h2>
+
+<center><i><b>What goes up, must come down...</b></i></center><p>
+
+The constructor and destructor of a plugin are defined as
+
+<p><table><tr><td bgcolor=#F0F0F0><pre><br>
+cPlugin(void);
+virtual ~cPlugin();
+</pre></td></tr></table><p>
+
+The <b>constructor</b> shall initialize any member variables the plugin defines, but
+<b>must not access any global structures of VDR</b>.
+It also must not create any threads or other large data structures. These things
+are done in the <a href="#Getting started"><tt>Start()</tt></a> function later.
+Constructing a plugin object shall not have any side effects or produce any output,
+since VDR, for instance, has to create the plugin objects in order to get their
+command line help - and after that immediately destroys them again.
+<p>
+The <b>destructor</b> has to clean up any data created by the plugin, and has to
+take care that any threads the plugin may have created will be stopped.
+<p>
+Of course, if your plugin doesn't define any member variables that need to be
+initialized (and deleted), you don't need to implement either of these functions.
+
+<hr><h2>Version number</h2>
+
+<center><i><b>Which incarnation is this?</b></i></center><p>
+
+Every plugin must have a version number of its own, which does not necessarily
+have to be in any way related to the VDR version number.
+VDR requests a plugin's version number through a call to the function
+
+<p><table><tr><td bgcolor=#F0F0F0><pre><br>
+virtual const char *Version(void) = 0;
+</pre></td></tr></table><p>
+
+Since this is a "pure" virtual function, any derived plugin class <b>must</b>
+implement it. The returned string should identify this version of the plugin.
+Typically this would be something like "0.0.1", but it may also contain other
+information, like for instance "0.0.1pre2" or the like. The string should only
+be as long as really necessary, and shall not contain the plugin's name itself.
+Here's an example:
+
+<p><table><tr><td bgcolor=#F0F0F0><pre><br>
+static const char *VERSION = "0.0.1";
+
+...
+
+const char *cPluginDemo::Version(void)
+{
+ return VERSION;
+}
+</pre></td></tr></table><p>
+
+Note that the definition of the version number is expected to be located in the
+main source file, and must be written as
+<pre>
+static const char *VERSION = ...
+</pre>
+just like shown in the above example. This is a convention that allows the <tt>Makefile</tt>
+to extract the version number when generating the file name for the distribution archive.
+<p>
+A new plugin project should start with version number <tt>0.0.1</tt> and should reach
+version <tt>1.0.0</tt> once it is completely operative and well tested. Following the
+Linux kernel version numbering scheme, versions with <i>even</i> release numbers
+(like <tt>1.0.x</tt>, <tt>1.2.x</tt>, <tt>1.4.x</tt>...) should be stable releases,
+while those with <i>odd</i> release numbers (like <tt>1.1.x</tt>, <tt>1.3.x</tt>,
+<tt>1.5.x</tt>...) are usually considered "under development". The three parts of
+a version number are not limited to single digits, so a version number of <tt>1.2.15</tt>
+would be acceptable.
+
+<hr><h2>Description</h2>
+
+<center><i><b>What is it that you do?</b></i></center><p>
+
+In order to tell the user what exactly a plugin does, it must implement the function
+
+<p><table><tr><td bgcolor=#F0F0F0><pre><br>
+virtual const char *Description(void) = 0;
+</pre></td></tr></table><p>
+
+which returns a short, one line description of the plugin's purpose.
+
+<p><table><tr><td bgcolor=#F0F0F0><pre><br>
+virtual const char *Description(void)
+{
+ return "A simple demo plugin";
+}
+</pre></td></tr></table><p>
+
+<hr><h2>Command line arguments</h2>
+
+<center><i><b>Taking orders</b></i></center><p>
+
+A VDR plugin can have command line arguments just like any normal program.
+If a plugin wants to react on command line arguments, it needs to implement
+the function
+
+<p><table><tr><td bgcolor=#F0F0F0><pre><br>
+virtual bool ProcessArgs(int argc, char *argv[]);
+</pre></td></tr></table><p>
+
+The parameters <tt>argc</tt> and <tt>argv</tt> have exactly the same meaning
+as in a normal C program's <tt>main()</tt> function.
+<tt>argv[0]</tt> contains the name of the plugin (as given in the <b><tt>-P</tt></b>
+option of the <tt>vdr</tt> call).
+<p>
+Each plugin has its own set of command line options, which are totally independent
+from those of any other plugin or VDR itself.
+<p>
+You can use the <tt>getopt()</tt> or <tt>getopt_long()</tt> function to process
+these arguments. As with any normal C program, the strings pointed to by <tt>argv</tt>
+will survive the entire lifetime of the plugin, so it is safe to store pointers to
+these values inside the plugin. Here's an example:
+
+<p><table><tr><td bgcolor=#F0F0F0><pre><br>
+bool cPluginDemo::ProcessArgs(int argc, char *argv[])
+{
+ static struct option long_options[] = {
+ { "aaa", required_argument, NULL, 'a' },
+ { "bbb", no_argument, NULL, 'b' },
+ { NULL }
+ };
+
+ int c;
+ while ((c = getopt_long(argc, argv, "a:b", long_options, NULL)) != -1) {
+ switch (c) {
+ case 'a': fprintf(stderr, "option -a = %s\n", optarg);
+ break;
+ case 'b': fprintf(stderr, "option -b\n");
+ break;
+ default: return false;
+ }
+ }
+ return true;
+}
+</pre></td></tr></table><p>
+
+The return value must be <i>true</i> if all options have been processed
+correctly, or <i>false</i> in case of an error. The first plugin that returns
+<i>false</i> from a call to its <tt>ProcessArgs()</tt> function will cause VDR
+to exit.
+
+<hr><h2>Command line help</h2>
+
+<center><i><b>Tell me about it...</b></i></center><p>
+
+If a plugin accepts command line options, it should implement the function
+
+<p><table><tr><td bgcolor=#F0F0F0><pre><br>
+virtual const char *CommandLineHelp(void);
+</pre></td></tr></table><p>
+
+which will be called if the user enters the <b><tt>-h</tt></b> option when starting VDR.
+The returned string should contain the command line help for this plugin, formatted
+in the same way as done by VDR itself:
+
+<p><table><tr><td bgcolor=#F0F0F0><pre><br>
+const char *cPluginDemo::CommandLineHelp(void)
+{
+ return " -a ABC, --aaa=ABC do something nice with ABC\n"
+ " -b, --bbb activate 'plan B'\n";
+}
+</pre></td></tr></table><p>
+
+This command line help will be printed directly below VDR's help texts (separated
+by a line indicating the plugin's name, version and description), so if you use the
+same formatting as shown here it will line up nicely.
+Note that all lines should be terminated with a newline character, and should
+be shorter than 80 characters.
+
+<a name="Getting started"><hr><h2>Getting started</h2>
+
+<center><i><b>Let's get ready to rumble!</b></i></center><p>
+
+If a plugin implements a function that runs in the background (presumably in a
+thread of its own), or wants to make use of <a href="#Internationalization">internationalization</a>,
+it needs to implement the function
+
+<p><table><tr><td bgcolor=#F0F0F0><pre><br>
+virtual void Start(void);
+</pre></td></tr></table><p>
+
+which is called once for each plugin at program startup.
+Inside this function the plugin must set up everything necessary to perform
+its task. This may, for instance, be a thread that collects data from the DVB
+stream, which is later presented to the user via a function that is available
+from the main menu.
+<p>
+If the plugin doesn't implement any background functionality or internationalized
+texts, it doesn't need to implement this function.
+
+<hr><h2>Main menu entry</h2>
+
+<center><i><b>Today's special is...</b></i></center><p>
+
+If the plugin implements a feature that the user shall be able to access
+from VDR's main menu, it needs to implement the function
+
+<p><table><tr><td bgcolor=#F0F0F0><pre><br>
+virtual const char *MainMenuEntry(void);
+</pre></td></tr></table><p>
+
+The default implementation returns a <tt>NULL</tt> pointer, which means that
+this plugin will not have an item in the main menu. Here's an example of a
+plugin that will have a main menu item:
+
+<p><table><tr><td bgcolor=#F0F0F0><pre><br>
+const char *cPluginDemo::MainMenuEntry(void)
+{
+ return "Demo";
+}
+</pre></td></tr></table><p>
+
+The menu entries of all plugins will be inserted into VDR's main menu right
+after the <i>Recordings</i> item, in the same sequence as they were given
+in the call to VDR.
+
+<hr><h2>User interaction</h2>
+
+<center><i><b>It's showtime!</b></i></center><p>
+
+If the user selects the main menu entry of a plugin, VDR calls the function
+
+<p><table><tr><td bgcolor=#F0F0F0><pre><br>
+virtual cOsdMenu *MainMenuAction(void);
+</pre></td></tr></table><p>
+
+which can do one of two things:
+<ul>
+<li>Return a pointer to a <tt>cOsdMenu</tt> object which will be displayed
+ as a submenu of the main menu (just like the <i>Recordings</i> menu, for instance).
+ That menu can then implement further functionality and, for instance, could
+ eventually start a custom player to replay a file other than a VDR recording.
+<li>Perform a specific action and return <tt>NULL</tt>. In that case the main menu
+ will be closed after calling <tt>MainMenuAction()</tt>.
+</ul>
+<b>
+It is very important that a call to <tt>MainMenuAction()</tt> returns as soon
+as possible! As long as the program stays inside this function, no other user
+interaction is possible. If a specific action takes longer than a few seconds,
+the plugin should launch a separate thread to do this.
+</b>
+
+<hr><h2>Setup parameters</h2>
+
+<center><i><b>Remember me...</b></i></center><p>
+
+If a plugin requires its own setup parameters, it needs to implement the following
+functions to handle these parameters:
+
+<p><table><tr><td bgcolor=#F0F0F0><pre><br>
+virtual cMenuSetupPage *SetupMenu(void);
+virtual bool SetupParse(const char *Name, const char *Value);
+</pre></td></tr></table><p>
+
+The <tt>SetupMenu()</tt> function shall return the plugin's "Setup" menu
+page, where the user can adjust all the parameters known to this plugin.
+<p>
+<tt>SetupParse()</tt> will be called for each parameter the plugin has
+previously stored in the global setup data (see below). It shall return
+<i>true</i> if the parameter was parsed correctly, <i>false</i> in case of
+an error. If <i>false</i> is returned, an error message will be written to
+the log file (and program execution will continue).
+<p>
+The plugin's setup parameters are stored in the same file as VDR's parameters.
+In order to allow each plugin (and VDR itself) to have its own set of parameters,
+the <tt>Name</tt> of each parameter will be preceeded with the plugin's
+name, as in
+<p>
+<tt>demo.SomeParameter = 123</tt>
+<p>
+The prefix will be handled by the core VDR setup code, so the individual
+plugins need not worry about this.
+<p>
+To store its values in the global setup, a plugin has to call the function
+
+<p><table><tr><td bgcolor=#F0F0F0><pre><br>
+void SetupStore(const char *Name, <i>type</i> Value);
+</pre></td></tr></table><p>
+
+where <tt>Name</tt> is the name of the parameter (<tt>"SomeParameter"</tt> in the above
+example, without the prefix <tt>"demo."</tt>) and <tt>Value</tt> is a simple data type (like
+<tt>char&nbsp;*</tt>, <tt>int</tt> etc).
+Note that this is not a function that the individual plugin class needs to implement!
+<tt>SetupStore()</tt> is a non-virtual member function of the <tt>cPlugin</tt> class.
+<p>
+To remove a parameter from the setup data, call <tt>SetupStore()</tt> with the appropriate
+name and without any value, as in
+<p>
+<tt>SetupStore("SomeParameter");</tt>
+<p>
+The VDR menu "Setup/Plugins" will list all loaded plugins with their name,
+version number and description. Selecting an item in this list will bring up
+the plugin's "Setup" menu if that plugin has implemented the <tt>SetupMenu()</tt>
+function.
+<p>
+Finally, a plugin doesn't have to implement the <tt>SetupMenu()</tt> if it only
+needs setup parameters that are not directly user adjustable. It can use
+<tt>SetupStore()</tt> and <tt>SetupParse()</tt> without presenting these
+parameters to the user.
+
+<a name="Internationalization"><hr><h2>Internationalization</h2>
+
+<center><i><b>Welcome to Babylon!</b></i></center><p>
+
+If a plugin displays texts to the user, it should implement internationalized
+versions of these texts and call the function
+
+<p><table><tr><td bgcolor=#F0F0F0><pre><br>
+void RegisterI18n(const tI18nPhrase * const Phrases);
+</pre></td></tr></table><p>
+
+to register them with VDR's internationalization mechanism.
+<p>
+The call to this function must be done in the <a href="#Getting started"><tt>Start()</tt></a> function of the plugin:
+
+<p><table><tr><td bgcolor=#F0F0F0><pre><br>
+const tI18nPhrase Phrases[] = {
+ { "Hello world!",
+ "Hallo Welt!",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ },
+ { NULL }
+ };
+
+void cPluginDemo::Start(void)
+{
+ RegisterI18n(Phrases);
+}
+</pre></td></tr></table><p>
+
+Each entry of type <tt>tI18nPhrase</tt> must have exactly as many members as defined
+by the constant <tt>I18nNumLanguages</tt> in the file <tt>VDR/i18n.h</tt>, and the
+sequence of the various languages must be the same as defined in <tt>VDR/i18n.c</tt>.<br>
+<b>It is very important that the array is terminated with a <tt>{&nbsp;NULL&nbsp;}</tt>
+entry!</b>.
+<p>
+Usually you won't be able to fill in all the different translations by yourself, so
+you may want to contact the maintainers of these languages (listed in the file
+<tt>VDR/i18n.c</tt>) and ask them to provide the additional translations.
+<p>
+The actual runtime selection of the texts corresponding to the selected language
+is done by wrapping each internationalized text with the <tt>tr()</tt> macro:
+
+<p><table><tr><td bgcolor=#F0F0F0><pre><br>
+const char *s = tr("Hello world!");
+</pre></td></tr></table><p>
+
+The text given here must be the first one defined in the related <i>Phrases</i>
+entry (which is the English version), and the returned pointer is either a translated
+version (if available) or the original string. In the latter case a message will be
+written to the log file, indicating that a translation is missing.
+Texts are first searched for in the <i>Phrases</i> registered for this plugin (if any)
+and then in the global VDR texts. So a plugin can make use of texts defined by the
+core VDR code.
+
+<a name="Loading plugins into VDR"><hr><h2>Loading plugins into VDR</h2>
+
+<center><i><b>Saddling up!</b></i></center><p>
+
+Plugins are loaded into VDR using the command line option <b><tt>-P</tt></b>, as in
+
+<p><table><tr><td bgcolor=#F0F0F0><pre><br>
+vdr -Pdemo
+</pre></td></tr></table><p>
+
+If the plugin accepts command line options, they are given as part of the argument
+to the <b><tt>-P</tt></b> option, which then has to be enclosed in quotes:
+
+<p><table><tr><td bgcolor=#F0F0F0><pre><br>
+vdr -P"demo -a abc -b"
+</pre></td></tr></table><p>
+
+Any number of plugins can be loaded this way, each with its own <b><tt>-P</tt></b> option:
+
+<p><table><tr><td bgcolor=#F0F0F0><pre><br>
+vdr -P"demo -a abc -b" -Pdvd -Pmp3
+</pre></td></tr></table><p>
+
+If you are not starting VDR from the VDR source directory (and thus your plugins
+cannot be found at their default location) you need to tell VDR the location of
+the plugins through the <b><tt>-L</tt></b> option:
+
+<p><table><tr><td bgcolor=#F0F0F0><pre><br>
+vdr -L/usr/lib/vdr -Pdemo
+</pre></td></tr></table><p>
+
+There can be any number of <b><tt>-L</tt></b> options, and each of them will apply to the
+<b><tt>-P</tt></b> options following it.
+<p>
+When started with the <b><tt>-h</tt></b> or <b><tt>-V</tt></b> option (for <i>help</i>
+or <i>version</i> information, respectively), VDR will automatically load all plugins
+in the default or given directory that match the VDR plugin
+<a href="#The plugin directory structure">naming convention</a>,
+and display their help and/or version information in addition to its own output.
+
+<a name="Building the distribution package"><hr><h2>Building the distribution package</h2>
+
+<center><i><b>Let's get this show on the road!</b></i></center><p>
+
+If you want to make your plugin available to other VDR users, you'll need to
+make a package that can be easily distributed.
+The <tt>Makefile</tt> that has been created by the call to
+<a href="#Initializing a new plugin directory"><tt>newplugin</tt></a>
+provides the target <tt>package</tt>, which does this for you.
+<p>
+Simply change into your source directory and execute <tt>make package</tt>:
+
+<p><table><tr><td bgcolor=#F0F0F0><pre><br>
+cd VDR/PLUGINS/SRC/demo
+make package
+</pre></td></tr></table><p>
+
+After this you should find a file named like
+
+<p><table><tr><td bgcolor=#F0F0F0><pre><br>
+vdr-demo-0.0.1.tgz
+</pre></td></tr></table><p>
+
+in your source directory, where <tt>demo</tt> will be replaced with your actual
+plugin's name, and <tt>0.0.1</tt> will be your plugin's current version number.
+
+</body>
+</html>
diff --git a/PLUGINS/SRC/hello/COPYING b/PLUGINS/SRC/hello/COPYING
new file mode 100644
index 0000000..5b6e7c6
--- /dev/null
+++ b/PLUGINS/SRC/hello/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/PLUGINS/SRC/hello/HISTORY b/PLUGINS/SRC/hello/HISTORY
new file mode 100644
index 0000000..b35760c
--- /dev/null
+++ b/PLUGINS/SRC/hello/HISTORY
@@ -0,0 +1,6 @@
+VDR Plugin 'hello' Revision History
+-----------------------------------
+
+2002-05-09: Version 0.0.1
+
+- Initial revision.
diff --git a/PLUGINS/SRC/hello/Makefile b/PLUGINS/SRC/hello/Makefile
new file mode 100644
index 0000000..fb764cd
--- /dev/null
+++ b/PLUGINS/SRC/hello/Makefile
@@ -0,0 +1,78 @@
+#
+# Makefile for a Video Disk Recorder plugin
+#
+# $Id: Makefile 1.1 2002/05/09 15:17:44 kls Exp $
+
+# The official name of this plugin.
+# This name will be used in the '-P...' option of VDR to load the plugin.
+# By default the main source file also carries this name.
+#
+PLUGIN = hello
+
+### The version number of this plugin (taken from the main source file):
+
+VERSION = `grep 'static const char \*VERSION *=' $(PLUGIN).c | awk '{ print $$6 }' | sed -e 's/[";]//g'`
+
+### The directory environment:
+
+DVBDIR = ../../../../DVB/ost/include
+VDRDIR = ../../..
+VDRINC = $(VDRDIR)/include
+LIBDIR = ../../lib
+TMPDIR = /tmp
+
+### The version number of VDR (taken from VDR's "config.h"):
+
+VDRVERSION = `grep 'define VDRVERSION ' $(VDRDIR)/config.h | awk '{ print $$3 }' | sed -e 's/"//g'`
+
+### The name of the distribution archive:
+
+ARCHIVE = vdr-$(PLUGIN)-$(VERSION)
+
+### Includes and Defines (add further entries here):
+
+INCLUDES = -I$(VDRINC) -I$(DVBDIR)
+
+DEFINES = -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
+
+### The object files (add further files here):
+
+OBJS = $(PLUGIN).o i18n.o
+
+### The C++ compiler and options:
+
+CXX = g++
+CXXFLAGS = -O2 -Wall -Woverloaded-virtual -m486
+
+### Implicit rules:
+
+%.o: %.c
+ $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
+
+# Dependencies:
+
+MAKEDEP = g++ -MM -MG
+DEPFILE = .dependencies
+$(DEPFILE): Makefile
+ @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
+
+include $(DEPFILE)
+
+### Targets:
+
+all: libvdr-$(PLUGIN).so
+
+libvdr-$(PLUGIN).so: $(OBJS)
+ $(CXX) $(CXXFLAGS) -shared $(OBJS) -o $@
+ @cp $@ $(LIBDIR)/$@.$(VDRVERSION)
+
+package: clean
+ @-rm -rf $(TMPDIR)/$(ARCHIVE)
+ @mkdir $(TMPDIR)/$(ARCHIVE)
+ @cp -a * $(TMPDIR)/$(ARCHIVE)
+ @tar czf $(ARCHIVE).tgz -C $(TMPDIR) $(ARCHIVE)
+ @-rm -rf $(TMPDIR)/$(ARCHIVE)
+ @echo Distribution archive created as $(ARCHIVE).tgz
+
+clean:
+ @-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~
diff --git a/PLUGINS/SRC/hello/README b/PLUGINS/SRC/hello/README
new file mode 100644
index 0000000..fd844ca
--- /dev/null
+++ b/PLUGINS/SRC/hello/README
@@ -0,0 +1,11 @@
+This is a "plugin" for the Video Disk Recorder (VDR).
+
+Written by: Klaus Schmidinger <kls@cadsoft.de>
+
+Project's homepage: www.cadsoft.de/people/kls/vdr
+
+Latest version available at: www.cadsoft.de/people/kls/vdr/software.htm
+
+See the file COPYING for license information.
+
+Description: This is a small demo of the VDR plugin interface.
diff --git a/PLUGINS/SRC/hello/hello.c b/PLUGINS/SRC/hello/hello.c
new file mode 100644
index 0000000..5db4f2a
--- /dev/null
+++ b/PLUGINS/SRC/hello/hello.c
@@ -0,0 +1,105 @@
+/*
+ * hello.c: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: hello.c 1.1 2002/05/09 15:28:51 kls Exp $
+ */
+
+#include <getopt.h>
+#include <vdr/interface.h>
+#include <vdr/plugin.h>
+#include "i18n.h"
+
+static const char *VERSION = "0.0.1";
+static const char *DESCRIPTION = "A friendly greeting";
+static const char *MAINMENUENTRY = "Hello";
+
+class cPluginHello : public cPlugin {
+private:
+ // Add any member variables or functions you may need here.
+ const char *option_a;
+ bool option_b;
+public:
+ cPluginHello(void);
+ virtual ~cPluginHello();
+ virtual const char *Version(void) { return VERSION; }
+ virtual const char *Description(void) { return tr(DESCRIPTION); }
+ virtual const char *CommandLineHelp(void);
+ virtual bool ProcessArgs(int argc, char *argv[]);
+ virtual void Start(void);
+ virtual const char *MainMenuEntry(void) { return tr(MAINMENUENTRY); }
+ virtual cOsdMenu *MainMenuAction(void);
+ virtual cMenuSetupPage *SetupMenu(void);
+ virtual bool SetupParse(const char *Name, const char *Value);
+ };
+
+cPluginHello::cPluginHello(void)
+{
+ // Initialize any member varaiables here.
+ // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL
+ // VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT!
+ option_a = NULL;
+ option_b = false;
+}
+
+cPluginHello::~cPluginHello()
+{
+ // Clean up after yourself!
+}
+
+const char *cPluginHello::CommandLineHelp(void)
+{
+ // Return a string that describes all known command line options.
+ return " -a ABC, --aaa=ABC do something nice with ABC\n"
+ " -b, --bbb activate 'plan B'\n";
+}
+
+bool cPluginHello::ProcessArgs(int argc, char *argv[])
+{
+ // Implement command line argument processing here if applicable.
+ static struct option long_options[] = {
+ { "aaa", required_argument, NULL, 'a' },
+ { "bbb", no_argument, NULL, 'b' },
+ { NULL }
+ };
+
+ int c;
+ while ((c = getopt_long(argc, argv, "a:b", long_options, NULL)) != -1) {
+ switch (c) {
+ case 'a': option_a = optarg;
+ break;
+ case 'b': option_b = true;
+ break;
+ default: return false;
+ }
+ }
+ return true;
+}
+
+void cPluginHello::Start(void)
+{
+ // Start any background activities the plugin shall perform.
+ RegisterI18n(Phrases);
+}
+
+cOsdMenu *cPluginHello::MainMenuAction(void)
+{
+ // Perform the action when selected from the main VDR menu.
+ Interface->Info(tr("Hello world!"));
+ return NULL;
+}
+
+cMenuSetupPage *cPluginHello::SetupMenu(void)
+{
+ // Return a setup menu in case the plugin supports one.
+ return NULL;
+}
+
+bool cPluginHello::SetupParse(const char *Name, const char *Value)
+{
+ // Parse your own setup parameters and store their values.
+ return false;
+}
+
+VDRPLUGINCREATOR(cPluginHello); // Don't touch this!
diff --git a/PLUGINS/SRC/hello/i18n.c b/PLUGINS/SRC/hello/i18n.c
new file mode 100644
index 0000000..7061742
--- /dev/null
+++ b/PLUGINS/SRC/hello/i18n.c
@@ -0,0 +1,52 @@
+/*
+ * i18n.c: Internationalization
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: i18n.c 1.1 2002/05/09 15:13:31 kls Exp $
+ */
+
+#include "i18n.h"
+
+const tI18nPhrase Phrases[] = {
+ { "Hello",
+ "Hallo",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ },
+ { "Hello world!",
+ "Hallo Welt!",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ },
+ { "A friendly greeting",
+ "Ein freundlicher Gruß",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ },
+ { NULL }
+ };
diff --git a/PLUGINS/SRC/hello/i18n.h b/PLUGINS/SRC/hello/i18n.h
new file mode 100644
index 0000000..2976fe8
--- /dev/null
+++ b/PLUGINS/SRC/hello/i18n.h
@@ -0,0 +1,11 @@
+/*
+ * i18n.h: Internationalization
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * $Id: i18n.h 1.1 2002/05/09 15:15:49 kls Exp $
+ */
+
+#include <vdr/i18n.h>
+
+extern const tI18nPhrase Phrases[];
diff --git a/channels.conf b/channels.conf
index db1cbf4..fef4774 100644
--- a/channels.conf
+++ b/channels.conf
@@ -48,83 +48,68 @@ ORB:12110:h:0:27500:501:502:504:0:28205
B1:12110:h:0:27500:601:602:604:0:28206
ARD Online-Kanal:12722:h:0:22000:0:701:0:0:0
:Premiere World
-Premiere World:11797:h:0:27500:255:256:32:0:8
-Premiere 1:11797:h:0:27500:511:512:0:101:10
-Premiere 2:11797:h:0:27500:1791:1792:0:101:11
+Premiere Start:11797:h:0:27500:255:256:0:101:8
+Premiere 1:11797:h:0:27500:511:512,513;515:0:101:10
+Premiere 2:11797:h:0:27500:1791:1792,1793;1795:0:101:11
Premiere 3:11797:h:0:27500:2303:2304:0:101:43
-Premiere One:12032:h:0:27500:3071:3072:0:101:51
-Premiere Star:11797:h:0:27500:767:768:0:101:9
-Premiere Sci-Fi:11797:h:0:27500:1535:1536:0:101:41
-Premiere Action:11797:h:0:27500:1023:1024:0:101:20
-Premiere X-Action:11798:h:0:27500:2047:2048:0:101:50
-Premiere Comedy:11797:h:0:27500:1279:1280:0:101:29
-13th Street:12031:h:0:27500:2303:2304:0:101:42
+Premiere 4:11797:h:0:27500:767:768:0:101:9
+Premiere 5:11797:h:0:27500:1279:1280:0:101:29
+Premiere 6:11797:h:0:27500:1535:1536:0:101:41
+Premiere 7:11797:h:0:27500:1023:1024:0:101:20
+13th Street:11758:h:0:27500:2303:2304:0:101:42
Studio Universal:12090:V:0:27500:255:256:0:101:36
-Filmpalast:12031:h:0:27500:2559:2560:0:101:516
-Heimatkanal:12031:h:0:27500:2815:2816:0:101:517
-Discovery Channel:12031:h:0:27500:1791:1792:0:101:14
-Planet:12090:V:0:27500:1279:1280:0:101:13
-Fox Kids:12031:h:0:27500:1279:1280:0:101:28
-Fox Kids Türkce:11914:H:0:27500:767:768:8191:101:54
-Junior:12031:h:0:27500:255:256:0:101:19
-K-Toon:12031:h:0:27500:511:512:0:101:12
+Premiere Serie:12031:h:0:27500:1023:1024:0:101:16
Disney Channel:12090:V:0:27500:767:768:0:101:34
-Sunset:12031:h:0:27500:1023:1024:0:101:16
+Premiere Nostalgie:12031:h:0:27500:2559:2560:0:101:516
+Discovery Channel:12031:h:0:27500:1791:1792:0:101:14
+Planet:12090:v:0:27500:1279:1280:0:101:13
+Fox Kids:11758:h:0:27500:1279:1280:0:101:28
+Junior:11758:h:0:27500:255:256:0:101:19
+K-Toon:11758:h:0:27500:511:512:0:101:12
Krimi&Co:12031:h:0:27500:1535:1536:0:101:23
-Goldstar TV:12031:h:0:27500:3839:3840:0:101:518
-Classica:12031:h:0:27500:767:768:0:101:15
-Seasons:12090:V:0:27500:511:512:0:101:33
-:Cinedom
-Cinedom Deluxe:11758:h:0:27500:255:256,257;259:0:101:189
-Cinedom 1A:11758:h:0:27500:511:512,513:0:101:190
-Cinedom 1B:12070:h:0:27500:1535:1536,1537:0:101:178
-Cinedom 1C:11720:h:0:27500:511:512,513:0:101:180
-Cinedom 1D:11720:h:0:27500:1535:1536,1537:0:101:176
-Cinedom 2A:11758:h:0:27500:1023:1024,1025:0:101:193
-Cinedom 2B:11720:h:0:27500:1279:1280:0:101:183
-Cinedom 2C:12070:h:0:27500:1791:1792:0:101:179
-Cinedom 2D:12070:h:0:27500:511:512:0:101:184
-Cinedom 2E:12070:h:0:27500:1279:1280:0:101:188
-Cinedom 3A:11758:h:0:27500:2559:2560:0:101:192
-Cinedom 3B:11758:h:0:27500:1535:1536:0:101:195
-Cinedom 3C:12070:h:0:27500:767:768:0:101:185
-Cinedom 3D:11720:h:0:27500:1023:1024:0:101:182
-Cinedom 4A:11758:h:0:27500:767:768:0:101:191
-Cinedom 4B:11720:h:0:27500:767:768:0:101:181
-Cinedom 4C:12070:h:0:27500:2047:2048:0:101:187
-Cinedom 5A:11758:h:0:27500:1279:1280:0:101:194
-Cinedom 5B:11720:h:0:27500:1791:1792:0:101:177
-Cinedom 5C:12070:h:0:27500:1023:1024:0:101:186
-:Beta Digital
-N24:12480:v:0:27500:2047:2048:0:0:47
-CNBC:11954:h:0:27500:510:520:0:0:28010
-Liberty TV.com:12610:V:0:22000:941:943,942:0:0:12199
+Goldstar TV:11758:h:0:27500:3839:3840:0:101:518
+Classica:11758:h:0:27500:767:768:0:101:15
+Sonnenklar TV:12090:V:0:27500:1023:1024:0:0:32
+:Premiere Direkt
+Premiere Direkt 1A:12031:h:0:27500:511:512,513;515:0:101:177
+Premiere Direkt 1B:11719:h:0:27500:1023:1024,1025;1027:0:101:182
+Premiere Direkt 2A:12031:h:0:27500:255:256;259:0:101:176
+Premiere Direkt 2B:11719:h:0:27500:767:768;769:0:101:181
+Premiere Direkt 3A:11719:h:0:27500:511:512;515:0:101:180
+Premiere Direkt 3B:11719:h:0:27500:1279:1280;1283:0:101:183
+Premiere Direkt 4A:12031:h:0:27500:2815:2816:0:101:18
+Premiere Direkt 4B:12070:h:0:27500:1535:1536:0:101:216
:PW Erotic
-Beate-Uhse.TV:11758:h:0:27500:3839:3840:0:101:21
-Blue Movie 1:11758:h:0:27500:1791:1792:0:101:513
-Blue Movie 2:11758:h:0:27500:2047:2048:0:101:514
-Blue Movie 3:11758:h:0:27500:2303:2304:0:101:515
+Beate-Uhse.TV:11758:h:0:27500:1023:1024:0:101:21
+Premiere Erotik 1:12031:h:0:27500:1279:1280:0:101:513
+Premiere Erotik 2:11719:h:0:27500:1535:1536:0:101:778
+Premiere Erotik 3:11719:h:0:27500:1791:1792:0:101:779
+Premiere Erotik 4:11719:h:0:27500:3583:3584:0:101:780
:Sportsworld
Premiere Sport 1:11720:h:0:27500:255:256,257:0:101:17
-Premiere Sport 2:12070:h:0:27500:3839:3840:0:101:27
-Premiere Sport 3:12070:h:0:27500:255:256:0:101:26
+Premiere Sport 2:12031:h:0:27500:3839:3840:0:101:27
:Formel 1
-Infokanal:11720:h:0:27500:3071:3072:0:101:244
-Multikanal:11720:h:0:27500:2815:2816:0:101:243
-Supersignal:11720:h:0:27500:255:256:0:101:17
-Verfolgerfeld:11720:h:0:27500:2303:2304:0:101:241
-Cockpitkanal:11720:h:0:27500:2559:2560:0:101:242
-Boxengasse:11720:h:0:27500:2047:2048:0:101:240
-:Premiere World Bundesliga
-Superdom:11758:h:0:27500:2815:8192:0:101:18
-BuLi-Konferenz:11758:h:0:27500:3327:3328,3329:0:101:215
-BuLi-Spiel 1:11720:h:0:27500:255:256,257:0:101:17
-BuLi-Spiel 2:11720:h:0:27500:2047:2048,2049:0:101:240
-BuLi-Spiel 3:11720:h:0:27500:2303:2304,2305:0:101:241
-BuLi-Spiel 4:11720:h:0:27500:2559:2560,2561:0:101:242
-BuLi-Spiel 5:11720:h:0:27500:2815:2816,2817:0:101:243
-BuLi-Spiel 6:11720:h:0:27500:3071:3072,3073:0:101:244
-BuLi-Spiel 7:11758:h:0:27500:3071:3072,3073:0:101:214
+Supersignal:12070:h:0:27500:255:256:0:101:211
+Cockpitkanal:12070:h:0:27500:511:512:0:101:212
+Boxengasse:12070:h:0:27500:767:768:0:101:213
+Verfolgerfeld:12070:h:0:27500:1023:1024:0:101:214
+Infokanal:12070:h:0:27500:1279:1280:0:101:215
+Multikanal:11720:h:0:27500:255:256:0:101:17
+:Beta Digital
+N24:12480:v:0:27500:2047:2048:0:0:47
+CNBC:11954:h:0:27500:510:520:0:0:28010
+Liberty TV.com:12610:V:0:22000:941:943,942:0:0:12199
+:Premiere Bundesliga
+BL-Konferenz:12031:h:0:27500:2303:2304,2305:0:101:210
+BuLi 1:11719:h:0:27500:255:256,257:0:101:17
+BuLi 2:11719:h:0:27500:2047:2048,2049:0:101:240
+BuLi 3:11719:h:0:27500:2303:2304,2305:0:101:241
+BuLi 4:11719:h:0:27500:2559:2560,2561:0:101:242
+BuLi 5:11719:h:0:27500:2815:2816,2817:0:101:243
+BuLi 6:11719:h:0:27500:3071:3072,3073:0:101:244
+BuLi 7:11719:h:0:27500:3327:3328,3329:0:101:245
+BuLi 8:12031:h:0:27500:3071:3072,3073:0:101:208
+BuLi 9:12031:h:0:27500:3327:3328,3329:0:101:209
:
TV Niepokalanow:11876:h:0:27500:305:321:0:0:20601
Mosaico:11934:v:0:27500:165:100:0:0:29010
@@ -168,7 +153,7 @@ ESC 1:12363:v:0:27500:163:104:0:0:0
TV5 Europe:12363:v:0:27500:164:112:0:0:0
TV7 Tunisia:12363:v:0:27500:166:128:0:0:0
ARTE:12363:v:0:27500:167:137:0:0:0
-RAI Uno:12363:v:0:27500:289:290:0:0:8904
+RAI Uno:10788:v:0:22000:289:290:0:0:9004
RTP International:12363:v:0:27500:300:301:0:0:0
Fashion TV:12402:v:0:27500:163:92:0:0:0
VideoService:12422:h:0:27500:255:256:0:0:0
diff --git a/channels.conf.cable b/channels.conf.cable
index b6d5c05..3987fd8 100644
--- a/channels.conf.cable
+++ b/channels.conf.cable
@@ -1,184 +1,165 @@
-:verschlüsselte Fernsehprogramm
-PREMIERE ONE:378:h:0:6900:3071:3072:0:1:51
-PREMIERE MOVIE 1:370:h:0:6900:511:512;515:0:1:10
-PREMIERE MOVIE 2:370:h:0:6900:1791:1792:0:1:11
-PREMIERE MOVIE 3:370:h:0:6900:2303:2304:0:1:43
-PREMIERE ACTION:370:h:0:6900:1023:1024,1025:0:1:20
-PREMIERE X-ACTION:370:h:0:6900:2047:2048,2049:0:1:50
-PREMIERE SCI-FI:370:h:0:6900:1535:1536:0:1:41
-PREMIERE STAR:370:h:0:6900:767:768:0:1:9
-PREMIERE COMEDY:370:h:0:6900:1279:1280:0:1:29
-13 TH STREET:378:h:0:6900:2303:2304,2305:0:1:42
-KRIMI &CO:378:h:0:6900:1535:1536:0:1:23
-STUDIO UNIVERSAL:402:h:0:6900:1050:1054:0:1:36
-DISCOVERY CHANNEL:378:h:0:6900:1791:1792:0:1:14
-FILMPALAST:378:h:0:6900:2559:2560:0:1:516
-DISNEY CHANNEL:402:h:0:6900:1030:1034:0:1:34
-SUNSET:378:h:0:6900:1023:1024:0:1:16
-PLANET:402:h:0:6900:1100:1104:0:1:13
-CLASSICA:378:h:0:6900:767:768:0:1:15
-GOLDSTAR TV:378:h:0:6900:3839:3840:0:1:518
-HEIMATKANAL:378:h:0:6900:2815:2816:0:1:517
-K-TOON:378:h:0:6900:511:512:0:1:12
-FOX KIDS:378:h:0:6900:1279:1280:0:1:28
-KiKa:394:h:0:6900:310:320:330:0:28008
-JUNIOR:378:h:0:6900:255:256:0:1:19
:Fernsehprogramme
-Das Erste:410:h:0:6900:101:102,88:104:0:28106
-ZDF:394:h:0:6900:110:120,121:130:0:28006
+Das Erste:410:h:0:6900:101:102:111:0:28106
+ZDF:394:h:0:6900:110:120:130:0:28006
+3sat:394:h:0:6900:210:220:230:0:28007
+arte:410:h:0:6900:401:402:404:0:28109
+EuroNews:394:h:0:6900:2221:2233:768:0:28015
ZDF.info:394:h:0:6900:610:620:0:0:28011
ZDF.doku:394:h:0:6900:660:670:0:0:28014
ZDF Theaterkanal:394:h:0:6900:1110:1120:130:0:28016
EinsExtra:426:h:0:6900:101:102:0:0:28201
EinsFestival:426:h:0:6900:201:202:0:0:28202
EinsMuXx:426:h:0:6900:301:302:0:0:28203
-3sat:394:h:0:6900:210:220:230:0:28007
-arte:410:h:0:6900:401:402:404:0:28109
-EuroNews:394:h:0:6900:2221:2233:768:0:28015
Phoenix:410:h:0:6900:901:902:0:0:28114
Eurosport:394:h:0:6900:410:420:430:0:28009
DW-tv:610:h:0:6900:634:632:0:0:6101
CNBC:394:h:0:6900:510:520:530:0:28010
+:Regionalprogramme
WDR FERNSEHEN:410:h:0:6900:601:602:604:0:28111
+B1 Berlin:426:h:0:6900:601:602,603:604:0:28206
+ORB-Fernsehen:426:h:0:6900:501:502:504:0:28205
MDR FERNSEHEN:426:h:0:6900:401:402:404:0:28204
SR Fernsehen Suedwest:410:h:0:6900:501:502:504:0:28110
SuedWest BW:410:h:0:6900:801:802:804:0:28113
SuedWest RP:426:h:0:6900:3101:3102:3104:0:28231
BR-alpha:410:h:0:6900:701:702:704:0:28112
-B1 Berlin:426:h:0:6900:601:602:604:0:28206
N3:426:h:0:6900:2401:2402:2404:0:28224
-ORB-Fernsehen:426:h:0:6900:501:502:504:0:28205
hessen fernsehen:410:h:0:6900:301:302:304:0:28108
Bayerisches FS:410:h:0:6900:201:202:204:0:28107
Test-R:410:h:0:6900:901:902:104:0:28130
+:Premiere Hauptprogramme
+Premiere START:370:C:0:6900:255:256:32:101:8
+Premiere 1:370:C:0:6900:511:512:0:101:10
+Premiere 2:370:C:0:6900:1791:1792:0:101:11
+Premiere 3:370:C:0:6900:2303:2304:0:101:43
+Premiere 4:370:C:0:6900:767:768:0:101:9
+Premiere 5:370:C:0:6900:1279:1280:0:101:29
+Premiere 6:370:C:0:6900:1535:1536:0:101:41
+Premiere 7:370:C:0:6900:1023:1024:0:101:20
+Premiere SERIE:378:C:0:6900:1023:1024:0:101:16
+Premiere Nostalgie:378:C:0:6900:2559:2560:0:101:516
+13 TH STREET:354:C:0:6900:2303:2304:0:101:42
+Stundio Universal:402:C:0:6900:1050:1054:0:101:36
+Krimi &Co:378:C:0:6900:1535:1536:0:101:23
+Disney Channel:402:C:0:6900:1030:1034:0:101:34
+Discovery Channel:378:C:0:6900:1791:1792:0:101:14
+Fox Kids:354:C:0:6900:1279:1280:0:101:28
+Junior:354:C:0:6900:255:256:0:101:19
+K-TOON:354:C:0:6900:0:0:0:101:12
+GOLDSTAR TV:354:C:0:6900:3839:3840:0:101:518
+CLASSICA:354:C:0:6900:767:768:0:101:15
:Mediavision
-Extreme Sport:346:h:0:6900:801:802:0:1:50700
-Bloomberg:346:h:0:6900:811:812:0:1:50701
-Single TV:346:h:0:6900:621:622:0:1:50706
-Fashion TV:346:h:0:6900:821:822:0:1:50702
-BET ON JAZZ:346:h:0:6900:841:842:0:1:50704
-LANDSCAPE:346:h:0:6900:831:832:0:1:50703
-Einstein:346:h:0:6900:623:624:0:1:50719
+Bloomberg:346:h:0:6900:811:812:0:101:50701
+Fashion TV:346:h:0:6900:821:822:0:101:50702
+Einstein:346:h:0:6900:623:624:0:101:50719
+Extreme Sport:346:h:0:6900:801:802:0:101:50700
+LANDSCAPE:346:h:0:6900:831:832:0:101:50703
+Single TV:346:h:0:6900:621:622:0:101:50706
Leitseite:346:h:0:6900:2254:0:0:0:5004
-Via 1 - Schöner Reisen:346:h:0:6900:611:612:0:0:50705
-Parlamentsfernsehen:610:h:0:6900:33:36:47:0:6100
-Vh1 - Classic:610:h:0:6900:604:603:0:0:6106
+BET ON JAZZ:346:h:0:6900:841:842:0:101:50704
+:Digit. Bouquet"Kabel Berlin"
+Parlamentsfernsehen:610:C:0:6900:33:36:47:0:6100
+DW-tv:610:C:0:6900:634:632:0:0:6101
+Kanal 7:610:C:0:6900:49:52:0:101:6103
+Euronews:610:C:0:6900:597:592,591:0:101:6104
+Vh1 - Classic:610:h:0:6900:604:603:0:101:6106
+Travel:610:C:0:6900:595:594:0:101:6105
+Nuvolari:618:C:0:6900:1011:1012:0:101:50101
+Marco Polo:618:C:0:6900:1021:1022:0:101:50102
+Alice:618:C:0:6900:1031:1032:0:101:50103
+Leonardo:618:C:0:6900:1041:1042:0:101:50104
+Club:618:C:0:6900:1051:1052:0:101:50105
+Avante:618:C:0:6900:1061:1062:0:101:50106
+Expo 24*7:618:C:0:6900:1071:1072:0:101:50107
+Innergy:618:C:0:6900:0:0:0:101:50108
+BBC Prime:618:C:0:6900:1091:1092:0:101:50109
+Eurosport News:618:C:0:6900:1101:1102:0:101:50110
:Diverse TV-Sender
-TV Polonia:434:h:0:6900:641:642:0:1:53204
-Kanal D:434:h:0:6900:651:652:0:1:53205
-RTP international:434:h:0:6900:661:662:0:1:53206
-ERT-Sat:434:h:0:6900:691:692:0:1:53209
-CNE:434:h:0:6900:4056:4057:0:1:53208
-ZEE TV:442:h:0:6900:517:773:0:1:53301
-NTV i:442:h:0:6900:514:515:0:1:53302
+TV Polonia:434:h:0:6900:641:642:0:101:53204
+Kanal D:434:h:0:6900:651:652:0:101:53205
+RTP international:434:h:0:6900:661:662:0:101:53206
+ERT-Sat:434:h:0:6900:691:692:0:101:53209
+CNE:434:h:0:6900:4056:4057:0:101:53208
+ZEE TV:442:h:0:6900:517:773:0:101:53301
+NTV i:442:h:0:6900:514:515:0:101:53302
ATV:434:h:0:6900:631:632:0:0:53203
TW1:610:h:0:6900:6106:6107:0:0:6106
-PREMIERE WORLD:370:h:0:6900:255:256:32:0:8
-:Premiere World Bundesliga
-Superdom:362:h:0:6900:255:256:0:1:26
-Spiel 1:362:h:0:6900:255:256,257:0:1:17
-Spiel 2:362:h:0:6900:2047:2048,2049:0:1:240
-BuLi-Konferenz:362:h:0:6900:3071:3072,3073:0:1:208
-BuLi-Spiel 1:362:h:0:6900:3327:3328,3329:0:1:209
-BuLi-Spiel 2:362:h:0:6900:2303:2304,2305:0:1:210
-BuLi-Spiel 3:362:h:0:6900:3583:3584,3585:0:1:211
-BuLi-Spiel 4:362:h:0:6900:2559:2560,2561:0:1:212
-BuLi-Spiel 5:362:h:0:6900:2815:2816,2817:0:1:213
:Premiere Sport
-PREMIERE SPORT 1:362:h:0:6900:255:256:0:1:17
-PREMIERE SPORT 2:362:h:0:6900:3327:3328:0:1:27
-PREMIERE SPORT 3:354:h:0:6900:2815:2816:0:1:18
-:Premiere Formel 1
-F1 Studio:362:h:0:6900:255:256:0:1:17
-F1 Box:362:h:0:6900:2047:2048:0:1:240
-F1 Verfolger:362:h:0:6900:2303:2304:0:1:241
-F1 Cockpit:362:h:0:6900:2559:2560:0:1:242
-F1 Multi:362:h:0:6900:2815:2816:0:1:243
-F1 Info:362:h:0:6900:3071:3072:0:1:244
-:Premiere Cinedom 1
-Cinedom 1A:362:h:0:6900:1535:1536,1537:0:1:176
-Cinedom 1B:386:h:0:6900:1535:1536,1537:0:1:178
-Cinedom 1C:362:h:0:6900:511:512,513:0:1:180
-Cinedom 1D:354:h:0:6900:511:512,513:0:1:190
-:Premiere Cinedom 2
-Cinedom 2A:386:h:0:6900:1791:1792,1793:0:1:179
-Cinedom 2B:362:h:0:6900:1279:1280,1281:0:1:183
-Cinedom 2C:386:h:0:6900:511:512:0:1:184
-Cinedom 2D:386:h:0:6900:1279:1280:0:1:188
-Cinedom 2E:354:h:0:6900:1023:1024:0:1:193
-: Premiere Cinedom 3
-Cinedom 3A:362:h:0:6900:1023:1024,1025:0:1:182
-Cinedom 3B:386:h:0:6900:767:768:0:1:185
-Cinedom 3C:354:h:0:6900:2559:2560:0:1:192
-Cinedom 3D:354:h:0:6900:1535:1536:0:1:195
-: Premiere Cinedom 4
-Cinedom 4A:362:h:0:6900:767:768,769:0:1:181
-Cinedom 4B:386:h:0:6900:2047:2048:0:1:187
-Cinedom 4C:354:h:0:6900:767:768:0:1:191
-: Premiere Cinedom 5
-Cinedom 5A:386:h:0:6900:1023:1024,1025:0:1:186
-Cinedom 5B:354:h:0:6900:1279:1280,1281:0:1:194
-: Premiere Cinedom Deluxe
-CINEDOM DELUXE:354:h:0:6900:255:256,257:0:1:189
-:Premiere Erotic
-BEATE-UHSE.TV:354:h:0:6900:3839:3840:0:1:21
-BLUE MOVIE 1:354:h:0:6900:1791:1792:0:1:513
-BLUE MOVIE 2:354:h:0:6900:2047:2048:0:1:514
-BLUE MOVIE 3:354:h:0:6900:2303:2304:0:1:515
+PREMIERE SPORT 1:362:C:0:6900:255:256,257:0:101:17
+PREMIERE SPORT 2:378:C:0:6900:3839:3840,3841:0:101:27
+:Premiere Direkt 1
+PREMIERE DIREKT 1A:362:C:0:6900:1023:1024,1025:0:101:182
+PREMIERE DIREKT 1B:378:C:0:6900:511:512,513:0:101:177
+:Premiere Direkt 2
+PREMIERE DIREKT 2A:378:C:0:6900:255:256,257:0:101:176
+PREMIERE DIREKT 2B:362:C:0:6900:767:768,769:0:101:181
+:Premiere Direkt 3
+PREMIERE DIREKT 3A:362:C:0:6900:511:512,513:0:101:180
+PREMIERE DIREKT 3B:362:C:0:6900:1279:1280,1281:0:101:183
+:Premiere Direkt 4
+PREMIERE DIREKT 4A:378:C:0:6900:2815:2816,2817:0:101:18
+PREMIERE DIREKT 4B:386:C:0:6900:1535:1536,1537:0:101:216
+:Premiere Erotik
+BEATE-UHSE.TV:354:C:0:6900:1023:1024:0:101:21
+PREMIERE EROTIK 1:378:C:0:6900:1279:1280:0:101:513
+PREMIERE EROTIK 2:362:C:0:6900:1535:1536:0:101:778
+PREMIERE EROTIK 3:362:C:0:6900:1791:1792:0:101:779
+PREMIERE EROTIK 4:362:C:0:6900:3583:3584:0:101:780
:Radioprogramme
-Fritz:426:h:0:6900:0:901:0:0:28209
-HR XXL:410:h:0:6900:0:3501:0:0:28125
-JUMP:426:h:0:6900:0:1001:0:0:28210
-SPUTNIK:426:h:0:6900:0:1201:0:0:28212
-RADIOmultikulti:426:h:0:6900:0:1301:0:0:28213
-DLR-Berlin:394:h:0:6900:0:710:0:0:28012
-DLF-Köln:394:h:0:6900:0:810:0:0:28013
-Österreich 1:394:h:0:6900:0:169:0:0:28017
-100,6:354:h:0:6900:0:1312:0:0:161
-Bayern 4 Klassik:410:h:0:6900:0:3001:0:0:28120
-B5 aktuell:410:h:0:6900:0:3101:0:0:28121
-Bremen 2:410:h:0:6900:0:3801:0:0:28128
-Bayern 1:410:h:0:6900:0:3601:0:0:28126
-NDR 4 Info:410:h:0:6900:0:3701:0:0:28127
-SR 1:410:h:0:6900:0:3901:0:0:28129
-hr-klassik:410:h:0:6900:0:3401:0:0:28124
-hr2:410:h:0:6900:0:3301:0:0:28123
-hr-chronos:410:h:0:6900:0:3201:0:0:28122
-Radio 3:426:h:0:6900:0:701:0:0:28207
-MDR KULTUR:426:h:0:6900:0:801:0:0:28208
-MDR info:426:h:0:6900:0:1101:0:0:28211
-SWR-2:426:h:0:6900:0:1401:0:0:28214
-WDR3:426:h:0:6900:0:1501:0:0:28215
-WDR Radio 5:426:h:0:6900:0:1601:0:0:28216
+Fritz:426:h:0:6900:1:901:0:0:28209
+HR XXL:410:h:0:6900:1:3501:0:0:28125
+JUMP:426:h:0:6900:1:1001:0:0:28210
+SPUTNIK:426:h:0:6900:1:1201:0:0:28212
+RADIOmultikulti:426:h:0:6900:1:1301:0:0:28213
+DLR-Berlin:394:h:0:6900:1:710:0:0:28012
+DLF-Köln:394:h:0:6900:1:810:0:0:28013
+Österreich 1:394:h:0:6900:1:169:0:0:28017
+100,6:354:h:0:6900:1:1312:0:0:161
+Bayern 4 Klassik:410:h:0:6900:1:3001:0:0:28120
+B5 aktuell:410:h:0:6900:1:3101:0:0:28121
+Bremen 2:410:h:0:6900:1:3801:0:0:28128
+Bayern 1:410:h:0:6900:1:3601:0:0:28126
+NDR 4 Info:410:h:0:6900:1:3701:0:0:28127
+SR 1:410:h:0:6900:1:3901:0:0:28129
+hr-klassik:410:h:0:6900:1:3401:0:0:28124
+hr2:410:h:0:6900:1:3301:0:0:28123
+hr-chronos:410:h:0:6900:1:3201:0:0:28122
+Radio 3:426:h:0:6900:1:701:0:0:28207
+MDR KULTUR:426:h:0:6900:1:801:0:0:28208
+MDR info:426:h:0:6900:1:1101:0:0:28211
+SWR-2:426:h:0:6900:1:1401:0:0:28214
+WDR3:426:h:0:6900:1:1501:0:0:28215
+WDR Radio 5:426:h:0:6900:1:1601:0:0:28216
:verschlüsselte Radioprogramme
-ALTERNATIVE ROCK:378:h:0:6900:1:800:0:1:151
-HITLISTE:378:h:0:6900:1:784:0:1:150
-DANCE:378:h:0:6900:1:816:0:1:152
-EASY LISTENING:402:h:0:6900:1:1201:0:1:162
-CLASSIC ROCK:378:h:0:6900:1:544:0:1:154
-Cristal New Age:442:h:0:6900:1:536:0:0:53351
-Movie Sounds:442:h:0:6900:1:537:0:1:53352
-LOVE SONGS:402:h:0:6900:1:1191:0:1:163
-KLASSIK POPULÄR:378:h:0:6900:1:592:0:1:145
-KLASS. SYMPHONIEN:378:h:0:6900:1:608:0:1:146
-OPER & VOKALMUSIK:378:h:0:6900:1:624:0:1:147
-BAROCKMUSIK:378:h:0:6900:1:640:0:1:148
-JAZZ:378:h:0:6900:1:656:0:1:149
-COUNTRY:378:h:0:6900:1:352:0:1:153
-FILMMUSIK:378:h:0:6900:1:368:0:1:155
-DEUTSCHE HITS:402:h:0:6900:1:1156:0:1:156
-SOUL CLASSICS:402:h:0:6900:1:1161:0:1:157
-TÜRK MÜZIGI:402:h:0:6900:1:1166:0:1:158
-GOLD:402:h:0:6900:1:1171:0:1:159
-MUSICALS:402:h:0:6900:1:1196:0:1:164
-OLD GOLD:402:h:0:6900:1:1186:0:1:165
-SCHLAGER:402:h:0:6900:1:1176:0:1:166
-VOLKSMUSIK:402:h:0:6900:1:1181:0:1:167
-All Jazz:442:h:0:6900:1:535:0:1:53350
-Sinfonica:442:h:0:6900:1:538:0:1:53353
-Opernfestival:442:h:0:6900:1:539:0:1:53354
-Barock Fantasie:442:h:0:6900:1:540:0:1:53355
-Musica Camerata:442:h:0:6900:1:541:0:1:53356
-Musica Antica:442:h:0:6900:1:542:0:1:53357
-Adagio:442:h:0:6900:1:543:0:1:53358
-Jazz Legends:442:h:0:6900:1:544:0:1:53359
+ALTERNATIVE ROCK:370:C:0:6900:1:800:0:101:151
+CLASSIC ROCK:370:C:0:6900:1:544:0:101:154
+DANCE:370:C:0:6900:1:816:0:101:152
+LOVE SONGS:370:C:0:6900:1:352:0:101:163
+GOLD:370:C:0:6900:1:576:0:101:159
+OLD GOLD:370:C:0:6900:1:304:0:101:165
+SOUL CLASSICS:370:C:0:6900:1:400:0:101:157
+EASY LISTENING:370:C:0:6900:1:384:0:101:162
+DEUTSCHE HITS:370:C:0:6900:1:592:0:101:156
+SCHLAGER:370:C:0:6900:1:320:0:101:166
+VOLKSMUSIK:362:C:0:6900:1:336:0:101:167
+COUNTRY:362:C:0:6900:1:352:0:101:153
+FILMMUSIK:362:C:0:6900:1:368:0:101:155
+MUSICALS:362:C:0:6900:1:384:0:101:164
+JAZZ:362:C:0:6900:1:656:0:101:149
+KLASSIK POPUL04R:378:C:0:6900:1:592:0:101:145
+ORCHESTRALE WERKE:378:C:0:6900:1:608:0:101:146
+BAROCK:378:C:0:6900:1:640:0:101:148
+OPER:378:C:0:6900:1:624:0:101:147
+TÜRK MÜZIGI:378:C:0:6900:1:560:0:101:158
+HITLISTE:370:C:0:6900:1:784:0:101:150
+Radio GoldStar:354:C:0:6900:1:368:0:101:171
+All Jazz:442:C:0:6900:1:535:0:101:53350
+Cristal New Age:442:C:0:6900:1:536:0:101:53351
+Movie Sounds:442:C:0:6900:1:537:0:101:53352
+Sinfonica:442:C:0:6900:1:538:0:101:53353
+Opernfestival:442:C:0:6900:1:539:0:101:53354
+Barock Fantasie:442:C:0:6900:1:540:0:101:53355
+Musica Camerata:442:C:0:6900:1:541:0:101:53356
+Musica Antica:442:C:0:6900:1:542:0:101:53357
+Adagio:442:C:0:6900:1:543:0:101:53358
+Jazz legends:442:C:0:6900:1:544:0:101:53359
diff --git a/channels.conf.terr b/channels.conf.terr
index bed1be8..81c0581 100644
--- a/channels.conf.terr
+++ b/channels.conf.terr
@@ -9,3 +9,12 @@ BBC CHOICE:505833:0:0:0:620:621:0:0:4351
BBC NEWS 24:505833:0:0:0:640:641:0:0:4415
BBC Knowledge:505833:0:0:0:630:631:0:0:4607
Shop!:561833:0:0:0:6049:6050:0:0:13120
+: DVB-T Berlin Germany
+RTL 1:778000:V:0:27500:160:80:0:1:1
+RTL 2:778000:V:0:27500:161:82:0:1:2
+Super RTL:778000:V:0:27500:162:84:0:1:3
+VOX:778000:V:0:27500:165:81:0:1:4
+SAT 1:714000:V:0:27500:160:80:0:1:18
+PRO 7:714000:V:0:27500:161:82:0:1:19
+KABEL 1:714000:V:0:27500:162:84:0:1:20
+N24:714000:V:0:27500:163:86:0:1:21
diff --git a/config.c b/config.c
index 76e138b..8290e73 100644
--- a/config.c
+++ b/config.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: config.c 1.97 2002/04/02 21:56:51 kls Exp $
+ * $Id: config.c 1.99 2002/05/05 09:10:00 kls Exp $
*/
#include "config.h"
@@ -13,6 +13,7 @@
#include "dvbapi.h"
#include "i18n.h"
#include "interface.h"
+#include "plugin.h"
// IMPORTANT NOTE: in the 'sscanf()' calls there is a blank after the '%d'
// format characters in order to allow any number of blanks after a numeric
@@ -332,7 +333,8 @@ cTimer::cTimer(bool Instant)
struct tm *now = localtime_r(&t, &tm_r);
day = now->tm_mday;
start = now->tm_hour * 100 + now->tm_min;
- stop = start + 200; // "instant recording" records 2 hours by default
+ stop = now->tm_hour * 60 + now->tm_min + Setup.InstantRecordTime;
+ stop = (stop / 60) * 100 + (stop % 60);
if (stop >= 2400)
stop -= 2400;
//TODO VPS???
@@ -386,11 +388,12 @@ cTimer& cTimer::operator= (const cTimer &Timer)
return *this;
}
-bool cTimer::operator< (const cTimer &Timer)
+bool cTimer::operator< (const cListObject &ListObject)
{
+ cTimer *ti = (cTimer *)&ListObject;
time_t t1 = StartTime();
- time_t t2 = (*(cTimer *)&Timer).StartTime();
- return t1 < t2 || (t1 == t2 && priority > Timer.priority);
+ time_t t2 = ti->StartTime();
+ return t1 < t2 || (t1 == t2 && priority > ti->priority);
}
const char *cTimer::ToText(cTimer *Timer)
@@ -916,12 +919,76 @@ const cCaDefinition *cCaDefinitions::Get(int Number)
return NULL;
}
+// -- cSetupLine -------------------------------------------------------------
+
+cSetupLine::cSetupLine(void)
+{
+ plugin = name = value = NULL;
+}
+
+cSetupLine::cSetupLine(const char *Name, const char *Value, const char *Plugin)
+{
+ name = strdup(Name);
+ value = strdup(Value);
+ plugin = Plugin ? strdup(Plugin) : NULL;
+}
+
+cSetupLine::~cSetupLine()
+{
+ delete plugin;
+ delete name;
+ delete value;
+}
+
+bool cSetupLine::operator< (const cListObject &ListObject)
+{
+ const cSetupLine *sl = (cSetupLine *)&ListObject;
+ if (!plugin && !sl->plugin)
+ return strcasecmp(name, sl->name) < 0;
+ if (!plugin)
+ return true;
+ if (!sl->plugin)
+ return false;
+ int result = strcasecmp(plugin, sl->plugin);
+ if (result == 0)
+ result = strcasecmp(name, sl->name);
+ return result < 0;
+}
+
+bool cSetupLine::Parse(char *s)
+{
+ char *p = strchr(s, '=');
+ if (p) {
+ *p = 0;
+ char *Name = compactspace(s);
+ char *Value = compactspace(p + 1);
+ if (*Name && *Value) {
+ p = strchr(Name, '.');
+ if (p) {
+ *p = 0;
+ char *Plugin = compactspace(Name);
+ Name = compactspace(p + 1);
+ if (!(*Plugin && *Name))
+ return false;
+ plugin = strdup(Plugin);
+ }
+ name = strdup(Name);
+ value = strdup(Value);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool cSetupLine::Save(FILE *f)
+{
+ return fprintf(f, "%s%s%s = %s\n", plugin ? plugin : "", plugin ? "." : "", name, value) > 0;
+}
+
// -- cSetup -----------------------------------------------------------------
cSetup Setup;
-char *cSetup::fileName = NULL;
-
cSetup::cSetup(void)
{
OSDLanguage = 0;
@@ -930,6 +997,7 @@ cSetup::cSetup(void)
MenuScrollPage = 1;
MarkInstantRecord = 1;
strcpy(NameInstantRecord, "TITLE EPISODE");
+ InstantRecordTime = 180;
LnbSLOF = 11700;
LnbFrequLo = 9750;
LnbFrequHi = 10600;
@@ -964,19 +1032,77 @@ cSetup::cSetup(void)
CurrentVolume = MAXVOLUME;
}
-void cSetup::PrintCaCaps(FILE *f, const char *Name)
+cSetup& cSetup::operator= (const cSetup &s)
+{
+ memcpy(&__BeginData__, &s.__BeginData__, (char *)&s.__EndData__ - (char *)&s.__BeginData__);
+ return *this;
+}
+
+cSetupLine *cSetup::Get(const char *Name, const char *Plugin)
+{
+ for (cSetupLine *l = First(); l; l = Next(l)) {
+ if ((l->Plugin() == NULL) == (Plugin == NULL)) {
+ if ((!Plugin || strcasecmp(l->Plugin(), Plugin) == 0) && strcasecmp(l->Name(), Name) == 0)
+ return l;
+ }
+ }
+ return NULL;
+}
+
+void cSetup::Store(const char *Name, const char *Value, const char *Plugin)
+{
+ if (Name && *Name) {
+ cSetupLine *l = Get(Name, Plugin);
+ if (l)
+ Del(l);
+ if (Value)
+ Add(new cSetupLine(Name, Value, Plugin));
+ }
+}
+
+void cSetup::Store(const char *Name, int Value, const char *Plugin)
+{
+ char *buffer = NULL;
+ asprintf(&buffer, "%d", Value);
+ Store(Name, buffer, Plugin);
+ delete buffer;
+}
+
+bool cSetup::Load(const char *FileName)
+{
+ if (cConfig<cSetupLine>::Load(FileName, true)) {
+ bool result = true;
+ for (cSetupLine *l = First(); l; l = Next(l)) {
+ if (l->Plugin()) {
+ cPlugin *p = cPluginManager::GetPlugin(l->Plugin());
+ if (p && !p->SetupParse(l->Name(), l->Value()))
+ result = false;
+ }
+ else {
+ if (!Parse(l->Name(), l->Value()))
+ result = false;
+ }
+ }
+ return result;
+ }
+ return false;
+}
+
+void cSetup::StoreCaCaps(const char *Name)
{
for (int d = 0; d < MAXDVBAPI; d++) {
- int written = 0;
+ char buffer[MAXPARSEBUFFER];
+ char *q = buffer;
+ *buffer = 0;
for (int i = 0; i < MAXCACAPS; i++) {
if (CaCaps[d][i]) {
- if (!written++)
- fprintf(f, "CaCaps = %d", d + 1);
- fprintf(f, " %d", CaCaps[d][i]);
+ if (!*buffer)
+ q += snprintf(buffer, sizeof(buffer), "%d", d + 1);
+ q += snprintf(q, sizeof(buffer) - (q - buffer), " %d", CaCaps[d][i]);
}
}
- if (written)
- fprintf(f, "\n");
+ if (*buffer)
+ Store(Name, buffer);
}
}
@@ -1003,142 +1129,99 @@ bool cSetup::ParseCaCaps(const char *Value)
return false;
}
-bool cSetup::Parse(char *s)
-{
- char *p = strchr(s, '=');
- if (p) {
- *p = 0;
- char *Name = compactspace(s);
- char *Value = compactspace(p + 1);
- if (*Name && *Value) {
- if (!strcasecmp(Name, "OSDLanguage")) OSDLanguage = atoi(Value);
- else if (!strcasecmp(Name, "PrimaryDVB")) PrimaryDVB = atoi(Value);
- else if (!strcasecmp(Name, "ShowInfoOnChSwitch")) ShowInfoOnChSwitch = atoi(Value);
- else if (!strcasecmp(Name, "MenuScrollPage")) MenuScrollPage = atoi(Value);
- else if (!strcasecmp(Name, "MarkInstantRecord")) MarkInstantRecord = atoi(Value);
- else if (!strcasecmp(Name, "NameInstantRecord")) strn0cpy(NameInstantRecord, Value, MaxFileName);
- else if (!strcasecmp(Name, "LnbSLOF")) LnbSLOF = atoi(Value);
- else if (!strcasecmp(Name, "LnbFrequLo")) LnbFrequLo = atoi(Value);
- else if (!strcasecmp(Name, "LnbFrequHi")) LnbFrequHi = atoi(Value);
- else if (!strcasecmp(Name, "DiSEqC")) DiSEqC = atoi(Value);
- else if (!strcasecmp(Name, "SetSystemTime")) SetSystemTime = atoi(Value);
- else if (!strcasecmp(Name, "TimeTransponder")) TimeTransponder = atoi(Value);
- else if (!strcasecmp(Name, "MarginStart")) MarginStart = atoi(Value);
- else if (!strcasecmp(Name, "MarginStop")) MarginStop = atoi(Value);
- else if (!strcasecmp(Name, "EPGScanTimeout")) EPGScanTimeout = atoi(Value);
- else if (!strcasecmp(Name, "EPGBugfixLevel")) EPGBugfixLevel = atoi(Value);
- else if (!strcasecmp(Name, "SVDRPTimeout")) SVDRPTimeout = atoi(Value);
- else if (!strcasecmp(Name, "SortTimers")) SortTimers = atoi(Value);
- else if (!strcasecmp(Name, "PrimaryLimit")) PrimaryLimit = atoi(Value);
- else if (!strcasecmp(Name, "DefaultPriority")) DefaultPriority = atoi(Value);
- else if (!strcasecmp(Name, "DefaultLifetime")) DefaultLifetime = atoi(Value);
- else if (!strcasecmp(Name, "UseSubtitle")) UseSubtitle = atoi(Value);
- else if (!strcasecmp(Name, "RecordingDirs")) RecordingDirs = atoi(Value);
- else if (!strcasecmp(Name, "VideoFormat")) VideoFormat = atoi(Value);
- else if (!strcasecmp(Name, "RecordDolbyDigital")) RecordDolbyDigital = atoi(Value);
- else if (!strcasecmp(Name, "ChannelInfoPos")) ChannelInfoPos = atoi(Value);
- else if (!strcasecmp(Name, "OSDwidth")) OSDwidth = atoi(Value);
- else if (!strcasecmp(Name, "OSDheight")) OSDheight = atoi(Value);
- else if (!strcasecmp(Name, "OSDMessageTime")) OSDMessageTime = atoi(Value);
- else if (!strcasecmp(Name, "MaxVideoFileSize")) MaxVideoFileSize = atoi(Value);
- else if (!strcasecmp(Name, "SplitEditedFiles")) SplitEditedFiles = atoi(Value);
- else if (!strcasecmp(Name, "MinEventTimeout")) MinEventTimeout = atoi(Value);
- else if (!strcasecmp(Name, "MinUserInactivity")) MinUserInactivity = atoi(Value);
- else if (!strcasecmp(Name, "MultiSpeedMode")) MultiSpeedMode = atoi(Value);
- else if (!strcasecmp(Name, "ShowReplayMode")) ShowReplayMode = atoi(Value);
- else if (!strcasecmp(Name, "CaCaps")) return ParseCaCaps(Value);
- else if (!strcasecmp(Name, "CurrentChannel")) CurrentChannel = atoi(Value);
- else if (!strcasecmp(Name, "CurrentVolume")) CurrentVolume = atoi(Value);
- else
- return false;
- return true;
- }
- }
- return false;
-}
-
-bool cSetup::Load(const char *FileName)
-{
- isyslog(LOG_INFO, "loading %s", FileName);
- delete fileName;
- fileName = strdup(FileName);
- FILE *f = fopen(fileName, "r");
- if (f) {
- int line = 0;
- char buffer[MAXPARSEBUFFER];
- bool result = true;
- while (fgets(buffer, sizeof(buffer), f) > 0) {
- line++;
- stripspace(buffer);
- if (!isempty(buffer)) {
- if (*buffer != '#' && !Parse(buffer)) {
- esyslog(LOG_ERR, "error in %s, line %d\n", fileName, line);
- result = false;
- }
- }
- }
- fclose(f);
- return result;
- }
+bool cSetup::Parse(const char *Name, const char *Value)
+{
+ if (!strcasecmp(Name, "OSDLanguage")) OSDLanguage = atoi(Value);
+ else if (!strcasecmp(Name, "PrimaryDVB")) PrimaryDVB = atoi(Value);
+ else if (!strcasecmp(Name, "ShowInfoOnChSwitch")) ShowInfoOnChSwitch = atoi(Value);
+ else if (!strcasecmp(Name, "MenuScrollPage")) MenuScrollPage = atoi(Value);
+ else if (!strcasecmp(Name, "MarkInstantRecord")) MarkInstantRecord = atoi(Value);
+ else if (!strcasecmp(Name, "NameInstantRecord")) strn0cpy(NameInstantRecord, Value, MaxFileName);
+ else if (!strcasecmp(Name, "InstantRecordTime")) InstantRecordTime = atoi(Value);
+ else if (!strcasecmp(Name, "LnbSLOF")) LnbSLOF = atoi(Value);
+ else if (!strcasecmp(Name, "LnbFrequLo")) LnbFrequLo = atoi(Value);
+ else if (!strcasecmp(Name, "LnbFrequHi")) LnbFrequHi = atoi(Value);
+ else if (!strcasecmp(Name, "DiSEqC")) DiSEqC = atoi(Value);
+ else if (!strcasecmp(Name, "SetSystemTime")) SetSystemTime = atoi(Value);
+ else if (!strcasecmp(Name, "TimeTransponder")) TimeTransponder = atoi(Value);
+ else if (!strcasecmp(Name, "MarginStart")) MarginStart = atoi(Value);
+ else if (!strcasecmp(Name, "MarginStop")) MarginStop = atoi(Value);
+ else if (!strcasecmp(Name, "EPGScanTimeout")) EPGScanTimeout = atoi(Value);
+ else if (!strcasecmp(Name, "EPGBugfixLevel")) EPGBugfixLevel = atoi(Value);
+ else if (!strcasecmp(Name, "SVDRPTimeout")) SVDRPTimeout = atoi(Value);
+ else if (!strcasecmp(Name, "SortTimers")) SortTimers = atoi(Value);
+ else if (!strcasecmp(Name, "PrimaryLimit")) PrimaryLimit = atoi(Value);
+ else if (!strcasecmp(Name, "DefaultPriority")) DefaultPriority = atoi(Value);
+ else if (!strcasecmp(Name, "DefaultLifetime")) DefaultLifetime = atoi(Value);
+ else if (!strcasecmp(Name, "UseSubtitle")) UseSubtitle = atoi(Value);
+ else if (!strcasecmp(Name, "RecordingDirs")) RecordingDirs = atoi(Value);
+ else if (!strcasecmp(Name, "VideoFormat")) VideoFormat = atoi(Value);
+ else if (!strcasecmp(Name, "RecordDolbyDigital")) RecordDolbyDigital = atoi(Value);
+ else if (!strcasecmp(Name, "ChannelInfoPos")) ChannelInfoPos = atoi(Value);
+ else if (!strcasecmp(Name, "OSDwidth")) OSDwidth = atoi(Value);
+ else if (!strcasecmp(Name, "OSDheight")) OSDheight = atoi(Value);
+ else if (!strcasecmp(Name, "OSDMessageTime")) OSDMessageTime = atoi(Value);
+ else if (!strcasecmp(Name, "MaxVideoFileSize")) MaxVideoFileSize = atoi(Value);
+ else if (!strcasecmp(Name, "SplitEditedFiles")) SplitEditedFiles = atoi(Value);
+ else if (!strcasecmp(Name, "MinEventTimeout")) MinEventTimeout = atoi(Value);
+ else if (!strcasecmp(Name, "MinUserInactivity")) MinUserInactivity = atoi(Value);
+ else if (!strcasecmp(Name, "MultiSpeedMode")) MultiSpeedMode = atoi(Value);
+ else if (!strcasecmp(Name, "ShowReplayMode")) ShowReplayMode = atoi(Value);
+ else if (!strcasecmp(Name, "CaCaps")) return ParseCaCaps(Value);
+ else if (!strcasecmp(Name, "CurrentChannel")) CurrentChannel = atoi(Value);
+ else if (!strcasecmp(Name, "CurrentVolume")) CurrentVolume = atoi(Value);
else
- LOG_ERROR_STR(FileName);
- return false;
+ return false;
+ return true;
}
-bool cSetup::Save(const char *FileName)
-{
- if (!FileName)
- FileName = fileName;
- if (FileName) {
- cSafeFile f(FileName);
- if (f.Open()) {
- fprintf(f, "# VDR Setup\n");
- fprintf(f, "OSDLanguage = %d\n", OSDLanguage);
- fprintf(f, "PrimaryDVB = %d\n", PrimaryDVB);
- fprintf(f, "ShowInfoOnChSwitch = %d\n", ShowInfoOnChSwitch);
- fprintf(f, "MenuScrollPage = %d\n", MenuScrollPage);
- fprintf(f, "MarkInstantRecord = %d\n", MarkInstantRecord);
- fprintf(f, "NameInstantRecord = %s\n", NameInstantRecord);
- fprintf(f, "LnbSLOF = %d\n", LnbSLOF);
- fprintf(f, "LnbFrequLo = %d\n", LnbFrequLo);
- fprintf(f, "LnbFrequHi = %d\n", LnbFrequHi);
- fprintf(f, "DiSEqC = %d\n", DiSEqC);
- fprintf(f, "SetSystemTime = %d\n", SetSystemTime);
- fprintf(f, "TimeTransponder = %d\n", TimeTransponder);
- fprintf(f, "MarginStart = %d\n", MarginStart);
- fprintf(f, "MarginStop = %d\n", MarginStop);
- fprintf(f, "EPGScanTimeout = %d\n", EPGScanTimeout);
- fprintf(f, "EPGBugfixLevel = %d\n", EPGBugfixLevel);
- fprintf(f, "SVDRPTimeout = %d\n", SVDRPTimeout);
- fprintf(f, "SortTimers = %d\n", SortTimers);
- fprintf(f, "PrimaryLimit = %d\n", PrimaryLimit);
- fprintf(f, "DefaultPriority = %d\n", DefaultPriority);
- fprintf(f, "DefaultLifetime = %d\n", DefaultLifetime);
- fprintf(f, "UseSubtitle = %d\n", UseSubtitle);
- fprintf(f, "RecordingDirs = %d\n", RecordingDirs);
- fprintf(f, "VideoFormat = %d\n", VideoFormat);
- fprintf(f, "RecordDolbyDigital = %d\n", RecordDolbyDigital);
- fprintf(f, "ChannelInfoPos = %d\n", ChannelInfoPos);
- fprintf(f, "OSDwidth = %d\n", OSDwidth);
- fprintf(f, "OSDheight = %d\n", OSDheight);
- fprintf(f, "OSDMessageTime = %d\n", OSDMessageTime);
- fprintf(f, "MaxVideoFileSize = %d\n", MaxVideoFileSize);
- fprintf(f, "SplitEditedFiles = %d\n", SplitEditedFiles);
- fprintf(f, "MinEventTimeout = %d\n", MinEventTimeout);
- fprintf(f, "MinUserInactivity = %d\n", MinUserInactivity);
- fprintf(f, "MultiSpeedMode = %d\n", MultiSpeedMode);
- fprintf(f, "ShowReplayMode = %d\n", ShowReplayMode);
- PrintCaCaps(f, "CaCaps");
- fprintf(f, "CurrentChannel = %d\n", CurrentChannel);
- fprintf(f, "CurrentVolume = %d\n", CurrentVolume);
- if (f.Close()) {
- isyslog(LOG_INFO, "saved setup to %s", FileName);
- return true;
- }
- }
+bool cSetup::Save(void)
+{
+ Store("OSDLanguage", OSDLanguage);
+ Store("PrimaryDVB", PrimaryDVB);
+ Store("ShowInfoOnChSwitch", ShowInfoOnChSwitch);
+ Store("MenuScrollPage", MenuScrollPage);
+ Store("MarkInstantRecord", MarkInstantRecord);
+ Store("NameInstantRecord", NameInstantRecord);
+ Store("InstantRecordTime", InstantRecordTime);
+ Store("LnbSLOF", LnbSLOF);
+ Store("LnbFrequLo", LnbFrequLo);
+ Store("LnbFrequHi", LnbFrequHi);
+ Store("DiSEqC", DiSEqC);
+ Store("SetSystemTime", SetSystemTime);
+ Store("TimeTransponder", TimeTransponder);
+ Store("MarginStart", MarginStart);
+ Store("MarginStop", MarginStop);
+ Store("EPGScanTimeout", EPGScanTimeout);
+ Store("EPGBugfixLevel", EPGBugfixLevel);
+ Store("SVDRPTimeout", SVDRPTimeout);
+ Store("SortTimers", SortTimers);
+ Store("PrimaryLimit", PrimaryLimit);
+ Store("DefaultPriority", DefaultPriority);
+ Store("DefaultLifetime", DefaultLifetime);
+ Store("UseSubtitle", UseSubtitle);
+ Store("RecordingDirs", RecordingDirs);
+ Store("VideoFormat", VideoFormat);
+ Store("RecordDolbyDigital", RecordDolbyDigital);
+ Store("ChannelInfoPos", ChannelInfoPos);
+ Store("OSDwidth", OSDwidth);
+ Store("OSDheight", OSDheight);
+ Store("OSDMessageTime", OSDMessageTime);
+ Store("MaxVideoFileSize", MaxVideoFileSize);
+ Store("SplitEditedFiles", SplitEditedFiles);
+ Store("MinEventTimeout", MinEventTimeout);
+ Store("MinUserInactivity", MinUserInactivity);
+ Store("MultiSpeedMode", MultiSpeedMode);
+ Store("ShowReplayMode", ShowReplayMode);
+ StoreCaCaps("CaCaps");
+ Store("CurrentChannel", CurrentChannel);
+ Store("CurrentVolume", CurrentVolume);
+
+ Sort();
+
+ if (cConfig<cSetupLine>::Save()) {
+ isyslog(LOG_INFO, "saved setup to %s", FileName());
+ return true;
}
- else
- esyslog(LOG_ERR, "attempt to save setup without file name");
return false;
}
-
diff --git a/config.h b/config.h
index 00774b0..3949dde 100644
--- a/config.h
+++ b/config.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: config.h 1.109 2002/04/07 13:08:12 kls Exp $
+ * $Id: config.h 1.113 2002/05/04 14:29:29 kls Exp $
*/
#ifndef __CONFIG_H
@@ -19,7 +19,7 @@
#include "eit.h"
#include "tools.h"
-#define VDRVERSION "1.0.0"
+#define VDRVERSION "1.1.0"
#define MAXPRIORITY 99
#define MAXLIFETIME 99
@@ -149,7 +149,7 @@ public:
cTimer(const cEventInfo *EventInfo);
virtual ~cTimer();
cTimer& operator= (const cTimer &Timer);
- bool operator< (const cTimer &Timer);
+ virtual bool operator< (const cListObject &ListObject);
const char *ToText(void);
bool Parse(const char *s);
bool Save(FILE *f);
@@ -220,7 +220,8 @@ private:
public:
cConfig(void) { fileName = NULL; }
virtual ~cConfig() { delete fileName; }
- virtual bool Load(const char *FileName, bool AllowComments = false)
+ const char *FileName(void) { return fileName; }
+ bool Load(const char *FileName, bool AllowComments = false)
{
Clear();
fileName = strdup(FileName);
@@ -323,20 +324,42 @@ extern cCommands Commands;
extern cSVDRPhosts SVDRPhosts;
extern cCaDefinitions CaDefinitions;
-class cSetup {
+class cSetupLine : public cListObject {
private:
- static char *fileName;
- void PrintCaCaps(FILE *f, const char *Name);
- bool ParseCaCaps(const char *Value);
+ char *plugin;
+ char *name;
+ char *value;
+public:
+ cSetupLine(void);
+ cSetupLine(const char *Name, const char *Value, const char *Plugin = NULL);
+ virtual ~cSetupLine();
+ virtual bool operator< (const cListObject &ListObject);
+ const char *Plugin(void) { return plugin; }
+ const char *Name(void) { return name; }
+ const char *Value(void) { return value; }
bool Parse(char *s);
+ bool Save(FILE *f);
+ };
+
+class cSetup : public cConfig<cSetupLine> {
+ friend class cPlugin; // needs to be able to call Store()
+private:
+ void StoreCaCaps(const char *Name);
+ bool ParseCaCaps(const char *Value);
+ bool Parse(const char *Name, const char *Value);
+ cSetupLine *Get(const char *Name, const char *Plugin = NULL);
+ void Store(const char *Name, const char *Value, const char *Plugin = NULL);
+ void Store(const char *Name, int Value, const char *Plugin = NULL);
public:
// Also adjust cMenuSetup (menu.c) when adding parameters here!
+ int __BeginData__;
int OSDLanguage;
int PrimaryDVB;
int ShowInfoOnChSwitch;
int MenuScrollPage;
int MarkInstantRecord;
char NameInstantRecord[MaxFileName];
+ int InstantRecordTime;
int LnbSLOF;
int LnbFrequLo;
int LnbFrequHi;
@@ -365,9 +388,11 @@ public:
int CaCaps[MAXDVBAPI][MAXCACAPS];
int CurrentChannel;
int CurrentVolume;
+ int __EndData__;
cSetup(void);
+ cSetup& operator= (const cSetup &s);
bool Load(const char *FileName);
- bool Save(const char *FileName = NULL);
+ bool Save(void);
};
extern cSetup Setup;
diff --git a/dvbapi.c b/dvbapi.c
index 9d59d90..77e5372 100644
--- a/dvbapi.c
+++ b/dvbapi.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: dvbapi.c 1.170 2002/04/07 09:35:51 kls Exp $
+ * $Id: dvbapi.c 1.174 2002/05/03 15:59:32 kls Exp $
*/
#include "dvbapi.h"
@@ -279,8 +279,7 @@ bool cIndexFile::Get(int Index, uchar *FileNumber, int *FileOffset, uchar *Pictu
int cIndexFile::GetNextIFrame(int Index, bool Forward, uchar *FileNumber, int *FileOffset, int *Length, bool StayOffEnd)
{
if (index) {
- if (Forward)
- CatchUp();
+ CatchUp();
int d = Forward ? 1 : -1;
for (;;) {
Index += d;
@@ -533,6 +532,8 @@ void cRecordBuffer::Input(void)
int w = Put(p, r);
p += w;
r -= w;
+ if (r > 0)
+ usleep(1); // this keeps the CPU load low
}
t = time(NULL);
}
@@ -1810,21 +1811,24 @@ bool cDvbApi::SetPrimaryDvbApi(int n)
return false;
}
-int cDvbApi::CanShift(int Ca, int Priority)
+int cDvbApi::CanShift(int Ca, int Priority, int UsedCards)
{
// Test whether a recording on this DVB device can be shifted to another one
// in order to perform a new recording with the given Ca and Priority on this device:
int ShiftLevel = -1; // default means this device can't be shifted
+ if (UsedCards & (1 << CardIndex()) != 0)
+ return ShiftLevel; // otherwise we would get into a loop
if (Recording()) {
if (ProvidesCa(Ca) // this device provides the requested Ca
&& (Ca != this->Ca() // the requested Ca is different from the one currently used...
|| Priority > this->Priority())) { // ...or the request comes from a higher priority
cDvbApi *d = NULL;
int Provides[MAXDVBAPI];
+ UsedCards |= (1 << CardIndex());
for (int i = 0; i < NumDvbApis; i++) {
if ((Provides[i] = dvbApi[i]->ProvidesCa(this->Ca())) != 0) { // this device is basicly able to do the job
if (dvbApi[i] != this) { // it is not _this_ device
- int sl = dvbApi[i]->CanShift(this->Ca(), Priority); // this is the original Priority!
+ int sl = dvbApi[i]->CanShift(this->Ca(), Priority, UsedCards); // this is the original Priority!
if (sl >= 0 && (ShiftLevel < 0 || sl < ShiftLevel)) {
d = dvbApi[i];
ShiftLevel = sl;
@@ -2301,16 +2305,17 @@ bool cDvbApi::SetPid(int fd, dmxPesType_t PesType, int Pid, dmxOutput_t Output)
{
if (Pid) {
CHECK(ioctl(fd, DMX_STOP));
- dmxPesFilterParams pesFilterParams;
- pesFilterParams.pid = Pid;
- pesFilterParams.input = DMX_IN_FRONTEND;
- pesFilterParams.output = Output;
- pesFilterParams.pesType = PesType;
- pesFilterParams.flags = DMX_IMMEDIATE_START;
- if (ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParams) < 0) {
- if (Pid != 0x1FFF)
+ if (Pid != 0x1FFF) {
+ dmxPesFilterParams pesFilterParams;
+ pesFilterParams.pid = Pid;
+ pesFilterParams.input = DMX_IN_FRONTEND;
+ pesFilterParams.output = Output;
+ pesFilterParams.pesType = PesType;
+ pesFilterParams.flags = DMX_IMMEDIATE_START;
+ if (ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParams) < 0) {
LOG_ERROR;
- return false;
+ return false;
+ }
}
}
return true;
diff --git a/dvbapi.h b/dvbapi.h
index e9cf8c8..7e63878 100644
--- a/dvbapi.h
+++ b/dvbapi.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: dvbapi.h 1.68 2002/03/10 10:50:00 kls Exp $
+ * $Id: dvbapi.h 1.69 2002/04/21 09:49:22 kls Exp $
*/
#ifndef __DVBAPI_H
@@ -104,7 +104,7 @@ private:
static int useDvbApi;
int cardIndex;
int caCaps[MAXCACAPS];
- int CanShift(int Ca, int Priority);
+ int CanShift(int Ca, int Priority, int UsedCards = 0);
public:
static cDvbApi *PrimaryDvbApi;
static void SetUseDvbApi(int n);
diff --git a/dvbosd.c b/dvbosd.c
index c348430..eb96261 100644
--- a/dvbosd.c
+++ b/dvbosd.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: dvbosd.c 1.12 2002/01/13 16:25:18 kls Exp $
+ * $Id: dvbosd.c 1.13 2002/04/13 11:34:48 kls Exp $
*/
#include "dvbosd.h"
@@ -25,6 +25,9 @@ cPalette::cPalette(int Bpp)
int cPalette::Index(eDvbColor Color)
{
+#if __BYTE_ORDER == __BIG_ENDIAN
+ Color = eDvbColor(((Color & 0xFF) << 24) | ((Color & 0xFF00) << 8) | ((Color & 0xFF0000) >> 8) | ((Color & 0xFF000000) >> 24));
+#endif
for (int i = 0; i < numColors; i++) {
if (color[i] == Color) {
used[i] = true;
diff --git a/i18n.c b/i18n.c
index 0b22f1d..4129cf7 100644
--- a/i18n.c
+++ b/i18n.c
@@ -4,26 +4,29 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: i18n.c 1.79 2002/04/06 09:49:19 kls Exp $
+ * $Id: i18n.c 1.87 2002/05/09 13:40:51 kls Exp $
*
- * Slovenian translations provided by Miha Setina <mihasetina@softhome.net> and Matjaz Thaler <matjaz.thaler@guest.arnes.si>
- * Italian translations provided by Alberto Carraro <bertocar@tin.it>
- * Dutch translations provided by Arnold Niessen <niessen@iae.nl> <arnold.niessen@philips.com>
- * Portuguese translations provided by Paulo Lopes <pmml@netvita.pt>
- * French translations provided by Jean-Claude Repetto <jc@repetto.org>
- * Norwegian translations provided by Jørgen Tvedt <pjtvedt@online.no> and Truls Slevigen <truls@slevigen.no>
- * Finnish translations provided by Hannu Savolainen <hannu@opensound.com>
- * Polish translations provided by Michael Rakowski <mrak@gmx.de>
- * Spanish translations provided by Ruben Nunez Francisco <ruben.nunez@tang-it.com>
+ * Translations provided by:
+ *
+ * Slovenian Miha Setina <mihasetina@softhome.net> and Matjaz Thaler <matjaz.thaler@guest.arnes.si>
+ * Italian Alberto Carraro <bertocar@tin.it>
+ * Dutch Arnold Niessen <niessen@iae.nl> <arnold.niessen@philips.com>
+ * Portuguese Paulo Lopes <pmml@netvita.pt>
+ * French Jean-Claude Repetto <jc@repetto.org>
+ * Norwegian Jørgen Tvedt <pjtvedt@online.no> and Truls Slevigen <truls@slevigen.no>
+ * Finnish Hannu Savolainen <hannu@opensound.com>
+ * Polish Michael Rakowski <mrak@gmx.de>
+ * Spanish Ruben Nunez Francisco <ruben.nunez@tang-it.com>
+ * Greek Dimitrios Dimitrakos <mail@dimitrios.de>
*
*/
/*
* How to add a new language:
*
- * 1. Announce your translation action on the Linux-DVB mailing
+ * 1. Announce your translation action on the VDR mailing
* list to avoid duplicate work.
- * 2. Increase the value of 'NumLanguages'.
+ * 2. Increase the value of 'I18nNumLanguages' in 'i18n.h'.
* 3. Insert a new line in every member of the 'Phrases[]' array,
* containing the translated text for the new language.
* For example, assuming you want to add the Italian language,
@@ -45,7 +48,7 @@
* Note that only the characters defined in 'fontosd.c' will
* be available!
* 4. Compile VDR and test the new language by switching to it
- * in the "Setup" menu.
+ * in the "Setup/OSD" menu.
* 5. Send the modified 'i18n.c' file to <kls@cadsoft.de> to have
* it included in the next version of VDR.
*
@@ -59,15 +62,10 @@
*/
#include "i18n.h"
-#include <stdio.h>
#include "config.h"
#include "tools.h"
-const int NumLanguages = 11;
-
-typedef const char *tPhrase[NumLanguages];
-
-const tPhrase Phrases[] = {
+const tI18nPhrase Phrases[] = {
// The name of the language (this MUST be the first phrase!):
{ "English",
"Deutsch",
@@ -80,6 +78,7 @@ const tPhrase Phrases[] = {
"Suomi",
"Polski",
"Español",
+ "Ellinika",
},
// Menu titles:
{ "VDR",
@@ -93,6 +92,7 @@ const tPhrase Phrases[] = {
"VDR",
"VDR",
"VDR",
+ "VDR",
},
{ "Schedule",
"Programm",
@@ -105,6 +105,7 @@ const tPhrase Phrases[] = {
"Ohjelmat",
"Program",
"Programa",
+ "Programma",
},
{ "Channels",
"Kanäle",
@@ -117,6 +118,7 @@ const tPhrase Phrases[] = {
"Kanavat",
"Kanaly",
"Canales",
+ "Kanalia",
},
{ "Timers",
"Timer",
@@ -129,6 +131,7 @@ const tPhrase Phrases[] = {
"Ajastin",
"Timery",
"Timer",
+ "Programmatismos",
},
{ "Recordings",
"Aufzeichnungen",
@@ -141,6 +144,7 @@ const tPhrase Phrases[] = {
"Nauhoitteet",
"Nagrania",
"Grabaciones",
+ "Egrafes",
},
{ "Setup",
"Einstellungen",
@@ -153,6 +157,7 @@ const tPhrase Phrases[] = {
"Asetukset",
"Nastawy",
"Configuración",
+ "Rithmisis",
},
{ "Commands",
"Befehle",
@@ -165,6 +170,7 @@ const tPhrase Phrases[] = {
"Komennot",
"Rozkazy",
"Órdenes",
+ "Entoles",
},
{ "Edit channel",
"Kanal editieren",
@@ -177,6 +183,7 @@ const tPhrase Phrases[] = {
"Muokkaa kanavaa",
"Ustawienie kanalu",
"Modificar canal",
+ "Prosarmoges kanaliou",
},
{ "Edit timer",
"Timer editieren",
@@ -189,6 +196,7 @@ const tPhrase Phrases[] = {
"Muokkaa ajastusta",
"Ustawienie timerow",
"Modificar timer",
+ "Prosarmoges programmatismou",
},
{ "Event",
"Sendung",
@@ -201,6 +209,7 @@ const tPhrase Phrases[] = {
"Tapahtuma",
"Audycja",
"Evento",
+ "Ekpompi",
},
{ "Summary",
"Inhalt",
@@ -213,6 +222,7 @@ const tPhrase Phrases[] = {
"Yhteenveto",
"Zawartosc",
"Resúmen",
+ "Periexomeno",
},
{ "Schedule - %s",
"Programm - %s",
@@ -225,6 +235,7 @@ const tPhrase Phrases[] = {
"Ohjelma - %s",
"Program - %s",
"Programa - %s",
+ "Programma - %s",
},
{ "What's on now?",
"Was läuft jetzt?",
@@ -237,6 +248,7 @@ const tPhrase Phrases[] = {
"Nykyinen ohjelma",
"Program biezacy",
"¿Qué hay ahora?",
+ "Ti pezi tora",
},
{ "What's on next?",
"Was läuft als nächstes?",
@@ -249,6 +261,7 @@ const tPhrase Phrases[] = {
"Seuraava ohjelma",
"Program nastepny",
"¿Qué hay proximo?",
+ "Ti tha peksi meta",
},
// Button texts (should not be more than 10 characters!):
{ "Edit",
@@ -262,6 +275,7 @@ const tPhrase Phrases[] = {
"Muuta",
"Edycja",
"Modificar",
+ "Prosarmogi",
},
{ "New",
"Neu",
@@ -274,6 +288,7 @@ const tPhrase Phrases[] = {
"Uusi",
"Nowy",
"Nuevo",
+ "Neo",
},
{ "Delete",
"Löschen",
@@ -286,6 +301,7 @@ const tPhrase Phrases[] = {
"Poista",
"Usunac",
"Borrar",
+ "Swisimo",
},
{ "Mark",
"Markieren",
@@ -298,6 +314,7 @@ const tPhrase Phrases[] = {
"Merkitse",
"Zaznaczyc",
"Marcar",
+ "Markarisma",
},
{ "On/Off",
"Ein/Aus",
@@ -310,6 +327,7 @@ const tPhrase Phrases[] = {
"Päällä/Pois",
"Zal./ Wyl.",
"On/Off",
+ "Energo/Klisto",
},
{ "Record",
"Aufnehmen",
@@ -322,6 +340,7 @@ const tPhrase Phrases[] = {
"Nauhoita",
"Nagrywac",
"Grabar",
+ "Egrafi",
},
{ "Play",
"Wiedergabe",
@@ -334,6 +353,7 @@ const tPhrase Phrases[] = {
"Toista",
"Odtwarzac",
"Play",
+ "Anametadosi",
},
{ "Rewind",
"Anfang",
@@ -346,6 +366,7 @@ const tPhrase Phrases[] = {
"Takaisinkel.",
"Poczatek",
"Rebobinar",
+ "Arxi",
},
{ "Button$Stop",
"Beenden",
@@ -358,6 +379,7 @@ const tPhrase Phrases[] = {
"Pysäytä",
"Zakonczyc",
"Parar",
+ "Terma",
},
{ "Resume",
"Weiter",
@@ -370,6 +392,7 @@ const tPhrase Phrases[] = {
"Jatka",
"Dalej",
"Continuar",
+ "Sinexia",
},
{ "Summary",
"Inhalt",
@@ -382,6 +405,7 @@ const tPhrase Phrases[] = {
"Yhteenveto",
"Zawartosc",
"Resumen",
+ "Periexomeno",
},
{ "Open",
"Öffnen",
@@ -394,6 +418,7 @@ const tPhrase Phrases[] = {
"Avaa",
"Otworzyc",
"Abrir",
+ "Anigma",
},
{ "Switch",
"Umschalten",
@@ -406,6 +431,7 @@ const tPhrase Phrases[] = {
"Valitse",
"Przelaczyc",
"Cambiar",
+ "Alagi",
},
{ "Now",
"Jetzt",
@@ -418,6 +444,7 @@ const tPhrase Phrases[] = {
"Nyt",
"Teraz",
"Ahora",
+ "Tora",
},
{ "Next",
"Nächste",
@@ -430,6 +457,7 @@ const tPhrase Phrases[] = {
"Seuraava",
"Nastepny",
"Siguiente",
+ "Epomeno",
},
{ "Button$Schedule",
"Programm",
@@ -442,6 +470,7 @@ const tPhrase Phrases[] = {
"Ohjelmisto",
"Program",
"Programa",
+ "Programma",
},
{ "Language",
"Sprache",
@@ -454,6 +483,7 @@ const tPhrase Phrases[] = {
"Kieli",
"Jezyk",
"Lengua",
+ "Glosa",
},
{ "Eject",
"Auswerfen",
@@ -466,6 +496,46 @@ const tPhrase Phrases[] = {
"Avaa",
"Wyrzucenie",
"Eyectar",
+ "Apovoli",
+ },
+ { "ABC/abc",
+ "ABC/abc",
+ "ABC/abc",
+ "ABC/abc",
+ "ABC/abc",
+ "ABC/abc",
+ "ABC/abc",
+ "ABC/abc",
+ "ABC/abc",
+ "ABC/abc",
+ "ABC/abc",
+ "ABC/abc",
+ },
+ { "Insert",
+ "Einfügen",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "Isodos",
+ },
+ { "Overwrite",
+ "Überschreiben",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "Epanagrafi",
},
// Confirmations:
{ "Delete channel?",
@@ -479,6 +549,7 @@ const tPhrase Phrases[] = {
"Poistetaanko kanava?",
"Usunac kanal?",
"¿Eliminar canal?",
+ "Na sviso to kanali?",
},
{ "Delete timer?",
"Timer löschen?",
@@ -491,6 +562,7 @@ const tPhrase Phrases[] = {
"Poistetaanko ajastus?",
"Usunac timer?",
"¿Eliminar timer?",
+ "Svisimo tou programmitismou?",
},
{ "Delete recording?",
"Aufzeichnung löschen?",
@@ -503,18 +575,20 @@ const tPhrase Phrases[] = {
"Poistetaanko nauhoitus?",
"Usunac nagranie?",
"¿Eliminar grabacion?",
+ "Svisimo tis egrafis?",
},
{ "Timer still recording - really delete?",
"Timer zeichnet auf - trotzdem löschen?",
"Snemanje po terminu - zares odstrani?",
"Timer in regestazione - cancello?",
- "Timer neemt nog op - toch verwijderen?"
+ "Timer neemt nog op - toch verwijderen?",
"Timer activo - têm a certeza que quer apagar?",
"Enregistrement en cours - confirmez la suppression",
"Timer gjør opptak - vil du slette likevel?",
"Ajastin nauhoittaa - poistetaanko silti?",
"Nagrywanie w trakcie - napewno usunac?",
"¿Timer activo - de verdad eliminarlo?",
+ "Ginete akoma programmatismeni egrafi - na svisti sigoura?",
},
{ "Stop recording?",
"Aufzeichnung beenden?",
@@ -527,6 +601,7 @@ const tPhrase Phrases[] = {
"Pysäytetäänkö nauhoitus?",
"Zakonczyc nagranie?",
"¿Parar grabación?",
+ "Akirosi egrafis?",
},
{ "on primary interface",
"auf dem primären Interface",
@@ -539,6 +614,7 @@ const tPhrase Phrases[] = {
"päävastaanottimella",
"na pierwszym interfejsie",
"en interface primario",
+ "stin protevon karta",
},
{ "Cancel editing?",
"Schneiden abbrechen?",
@@ -551,6 +627,7 @@ const tPhrase Phrases[] = {
"Peruutetaanko muokkaus?",
"Zakonczyc montaz?",
"¿Cancelar modificación?",
+ "Akirosi alagon?",
},
{ "Really restart?",
"Wirklich neu starten?",
@@ -563,6 +640,7 @@ const tPhrase Phrases[] = {
"Aloitetaanko varmasti alusta?",
"Rzeczywiscie nowy start?",
"¿De verdad reiniciar?",
+ "Na gini sigoura epanekinisi?",
},
{ "Recording - restart anyway?",
"Aufnahme läuft - trotzdem neu starten?",
@@ -575,6 +653,7 @@ const tPhrase Phrases[] = {
"Nauhoitus käynnissä - aloitetaanko alusta?",
"Nagrywanie w trakcie - rzeczywiscie nowy start?",
"¿Grabando - reiniciar?",
+ "Ginete egrafi - na gini epanekinisi sigoura?",
},
{ "Recording - shut down anyway?",
"Aufnahme läuft - trotzdem ausschalten?",
@@ -587,6 +666,7 @@ const tPhrase Phrases[] = {
"Nauhoitus kesken - lopetetaanko se?",
"Nagrywanie w trakcie - mimo to wylaczyc?",
"¿Grabando - apagar?",
+ "Ginete egrafi - na stamatisi i litourgia sigoura?",
},
{ "Recording in %d minutes, shut down anyway?",
"Aufnahme in %d Minuten - trotzdem ausschalten?",
@@ -599,6 +679,7 @@ const tPhrase Phrases[] = {
"Nauhoitus alkaisi %d min. kuluttua - sammutetaanko silti?",
"Nagrywanie za %d minut - mimo to wylaczyc?",
"¿Grabando en %d minutos, de verdad cortar?",
+ "Anamenete egrafi se %d lepta - na stamatisi i litourgia sigoura?",
},
{ "Press any key to cancel shutdown",
"Taste drücken um Shutdown abzubrechen",
@@ -611,6 +692,7 @@ const tPhrase Phrases[] = {
"Peruuta pysäytys painamalla jotakin näppäintä",
"Dowolny przycisk zatrzyma wylaczanie",
"Pulse una tecla para interrumpir corte",
+ "Piese ena pliktro na stamatisi to katevasma",
},
// Channel parameters:
{ "Name",
@@ -624,6 +706,7 @@ const tPhrase Phrases[] = {
"Nimi",
"Nazwa",
"Nombre",
+ "Onoma",
},
{ "Frequency",
"Frequenz",
@@ -636,6 +719,7 @@ const tPhrase Phrases[] = {
"Taajuus",
"Czestotliwosc",
"Frecuencia",
+ "Sixnotita",
},
{ "Polarization",
"Polarisation",
@@ -648,6 +732,7 @@ const tPhrase Phrases[] = {
"Polarisaatio",
"Polaryzacja",
"Polarización",
+ "Polosi",
},
{ "DiSEqC",
"DiSEqC",
@@ -660,6 +745,7 @@ const tPhrase Phrases[] = {
"DiSEqC",
"DiSEqC",
"DiSEqC",
+ "DiSEqC",
},
{ "Srate",
"Srate",
@@ -672,6 +758,7 @@ const tPhrase Phrases[] = {
"Srate",
"Srate",
"Srate",
+ "Srate",
},
{ "Vpid",
"Vpid",
@@ -684,6 +771,7 @@ const tPhrase Phrases[] = {
"Kuva PID",
"Vpid",
"Vpid",
+ "Vpid",
},
{ "Apid1",
"Apid1",
@@ -696,6 +784,7 @@ const tPhrase Phrases[] = {
"Ääni PID1",
"Apid1",
"Apid1",
+ "Apid1",
},
{ "Apid2",
"Apid2",
@@ -708,6 +797,7 @@ const tPhrase Phrases[] = {
"Ääni PID2",
"Apid2",
"Apid2",
+ "Apid2",
},
{ "Dpid1",
"Dpid1",
@@ -720,6 +810,7 @@ const tPhrase Phrases[] = {
"AC3 PID1",
"Dpid1",
"Dpid1",
+ "Dpid1",
},
{ "Dpid2",
"Dpid2",
@@ -732,6 +823,7 @@ const tPhrase Phrases[] = {
"AC3 PID2",
"Dpid2",
"Dpid2",
+ "Dpid2",
},
{ "Tpid",
"Tpid",
@@ -744,6 +836,7 @@ const tPhrase Phrases[] = {
"TekstiTV PID",
"Tpid",
"Tpid",
+ "Tpid",
},
{ "CA",
"CA",
@@ -756,6 +849,7 @@ const tPhrase Phrases[] = {
"Salauskortti",
"CA",
"CA",
+ "CA",
},
{ "Pnr",
"Pnr",
@@ -768,6 +862,7 @@ const tPhrase Phrases[] = {
"Ohjelmatunnus",
"Pnr",
"Pnr",
+ "Pnr",
},
// Timer parameters:
{ "Active",
@@ -781,6 +876,7 @@ const tPhrase Phrases[] = {
"Aktiivinen",
"Aktywny",
"Activo",
+ "Energo",
},
{ "Channel",
"Kanal",
@@ -793,6 +889,7 @@ const tPhrase Phrases[] = {
"Kanava",
"Kanal",
"Canal",
+ "Kanali",
},
{ "Day",
"Tag",
@@ -805,6 +902,7 @@ const tPhrase Phrases[] = {
"Päivä",
"Dzien",
"Día",
+ "Imera",
},
{ "Start",
"Anfang",
@@ -817,6 +915,7 @@ const tPhrase Phrases[] = {
"Aloitus",
"Poczatek",
"Comienzo",
+ "Arxi",
},
{ "Stop",
"Ende",
@@ -829,6 +928,7 @@ const tPhrase Phrases[] = {
"Lopetus",
"Koniec",
"Fin",
+ "Telos",
},
{ "Priority",
"Priorität",
@@ -841,6 +941,7 @@ const tPhrase Phrases[] = {
"Prioriteetti",
"Priorytet",
"Prioridad",
+ "Protereotita",
},
{ "Lifetime",
"Lebensdauer",
@@ -853,6 +954,7 @@ const tPhrase Phrases[] = {
"Voimassaolo",
"Trwalosc dni",
"Durabilidad",
+ "Xronos Zois",
},
{ "File",
"Datei",
@@ -865,6 +967,7 @@ const tPhrase Phrases[] = {
"Tiedosto",
"Plik",
"Fichero",
+ "Arxeio",
},
{ "First day",
"Erster Tag",
@@ -877,6 +980,7 @@ const tPhrase Phrases[] = {
"1. päivä",
"Pierwszy dzien",
"Primer día",
+ "Proti mera",
},
// Error messages:
{ "Channel is being used by a timer!",
@@ -890,6 +994,7 @@ const tPhrase Phrases[] = {
"Kanava on ajastimen käytössä!",
"Kanal jest zajety przez timer nagran",
"¡Canal está ocupado por un timer!",
+ "To kanali xrisimopiite apo programmatismeni thesi",
},
{ "Can't switch channel!",
"Kanal kann nicht umgeschaltet werden!",
@@ -902,6 +1007,7 @@ const tPhrase Phrases[] = {
"Kanavan vaihtaminen ei mahdollista!",
"Kanal nie moze byc teraz przelaczony!",
"¡No puedo cambiar canal!",
+ "Den mporo na pao sto kanali!",
},
{ "Timer is recording!",
"Timer zeichnet gerade auf!",
@@ -914,6 +1020,7 @@ const tPhrase Phrases[] = {
"Ajastinnauhoitus käynnissä!",
"Timer nagrywa!",
"¡Timer esta grabando!",
+ "Ginete progrmamatismeni egrafi!",
},
{ "Error while accessing recording!",
"Fehler beim Ansprechen der Aufzeichnung!",
@@ -926,6 +1033,7 @@ const tPhrase Phrases[] = {
"Nauhoituksen toistaminen epäonnistui!",
"Blad - brak dostepu do nagrania!",
"¡Error al accesar la grabación!",
+ "Lathos stin evresi tis egrafis!",
},
{ "Error while deleting recording!",
"Fehler beim Löschen der Aufzeichnung!",
@@ -938,6 +1046,7 @@ const tPhrase Phrases[] = {
"Nauhoituksen poistaminen epäonnistui!",
"Blad przy usuwaniu nagrania!",
"¡Error al borrar la grabación!",
+ "Lathos stin prospathia na svisti i egrafi!",
},
{ "*** Invalid Channel ***",
"*** Ungültiger Kanal ***",
@@ -950,6 +1059,7 @@ const tPhrase Phrases[] = {
"*** Virheellinen kanavavalinta! ***",
"*** Niewazny kanal ***",
"*** Canal inválido ***",
+ "*** Kanali akiro ***",
},
{ "No free DVB device to record!",
"Keine freie DVB-Karte zum Aufnehmen!",
@@ -962,6 +1072,7 @@ const tPhrase Phrases[] = {
"Ei vapaata vastaanotinta nauhoitusta varten!",
"Brak wolnej karty DVB do nagrywania!",
"¡No hay dispositivo DVB disponible para grabar!",
+ "Den iparxi elevteri DVB Karta gia egrafi!",
},
{ "Channel locked (recording)!",
"Kanal blockiert (zeichnet auf)!",
@@ -974,6 +1085,7 @@ const tPhrase Phrases[] = {
"Kanava lukittu (nauhoitusta varten)!",
"Kanal zablokowany (nagrywanie w toku)!",
"¡Canal bloqueado (grabando)!",
+ "To kanali ine mplokarismeno (Ginete egrafi)!",
},
{ "Can't start Transfer Mode!",
"Transfer-Mode kann nicht gestartet werden!",
@@ -986,6 +1098,7 @@ const tPhrase Phrases[] = {
"Käsittämättömiä teknisiä ongelmia!",
"Tryb transferowy jest niemozliwy!",
"¡No puedo iniciar modo de transferencia!",
+ "Den mpori na arxisi to Transfer-Mode!",
},
{ "Can't start editing process!",
"Schnitt kann nicht gestartet werden!",
@@ -998,6 +1111,7 @@ const tPhrase Phrases[] = {
"Muokkauksen aloittaminen ei onnistu!",
"Uruchamianie montazu jest niemozliwe!",
"¡No puedo iniciar proceso de modificación!",
+ "Den mpori na arxisi to kopsimo tis tenias!",
},
{ "Editing process already active!",
"Schnitt bereits aktiv!",
@@ -1010,6 +1124,7 @@ const tPhrase Phrases[] = {
"Muokkaus on jo käynnissä!",
"Montaz w toku!",
"¡Proceso de modificación ya fue iniciado!",
+ "To kopsimo ti tenias ini idi se litourgia!",
},
{ "Can't shutdown - option '-s' not given!",
"Shutdown unmöglich - Option '-s' fehlt!",
@@ -1020,8 +1135,9 @@ const tPhrase Phrases[] = {
"Arrêt impossible - option '-s' absente!",
"Kan ikke slå av - startet uten parameteret '-s'!",
"Ei voida sammuttaa '-s' parametria ei annettu!",
- "Wylaczenie niemozliwe - brak opcji '-s' !",
+ "Wylaczenie niemozliwe - brak opcji '-s'!",
"¡No puedo cortar - opción '-s' absente!",
+ "Den mporo na kliso ton ipologisti. Lipi i parametros '-s'!",
},
{ "Low disk space!",
"Platte beinahe voll!",
@@ -1034,6 +1150,7 @@ const tPhrase Phrases[] = {
"Kovalevy lähes täynnä!",
"Dysk wkrotce pelny!",
"¡Disco casi lleno",
+ "O Skliros kontevi na gemisi!",
},
// Setup pages:
{ "OSD",
@@ -1047,6 +1164,7 @@ const tPhrase Phrases[] = {
"Tekstinäyttö",
"OSD",
"OSD",
+ "OSD",
},
{ "EPG",
"EPG",
@@ -1059,6 +1177,7 @@ const tPhrase Phrases[] = {
"Ohjelmaopas",
"EPG",
"EPG",
+ "EPG",
},
{ "DVB",
"DVB",
@@ -1071,6 +1190,7 @@ const tPhrase Phrases[] = {
"DVB",
"DVB",
"DVB",
+ "DVB",
},
{ "LNB",
"LNB",
@@ -1083,6 +1203,7 @@ const tPhrase Phrases[] = {
"LNB",
"LNB",
"LNB",
+ "LNB",
},
{ "CICAM",
"CICAM",
@@ -1095,6 +1216,7 @@ const tPhrase Phrases[] = {
"CICAM",
"CICAM",
"CICAM",
+ "CICAM",
},
{ "Recording",
"Aufnahme",
@@ -1107,6 +1229,7 @@ const tPhrase Phrases[] = {
"Nauhoita",
"Nagranie",
"Grabación",
+ "Egrafi",
},
{ "Replay",
"Wiedergabe",
@@ -1119,6 +1242,7 @@ const tPhrase Phrases[] = {
"Toista",
"Odtwarzanie",
"Poner",
+ "Anametadosi",
},
{ "Miscellaneous",
"Sonstiges",
@@ -1131,6 +1255,20 @@ const tPhrase Phrases[] = {
"Sekalaista",
"Pozostale",
"Varios",
+ "Diafora",
+ },
+ { "Plugins",
+ "Plugins",
+ "Plugins",
+ "Plugins",
+ "Plugins",
+ "Plugins",
+ "Plugins",
+ "Plugins",
+ "Plugins",
+ "Plugins",
+ "Plugins",
+ "Plugins",
},
{ "Restart",
"Neustart",
@@ -1143,6 +1281,7 @@ const tPhrase Phrases[] = {
"Aloita uudelleen",
"Zastartowac",
"Reiniciar",
+ "Epanekinisi",
},
// Setup parameters:
{ "Setup.OSD$Language",
@@ -1156,6 +1295,7 @@ const tPhrase Phrases[] = {
"Kieli",
"Jezyk",
"Lengua",
+ "Glosa",
},
{ "Setup.OSD$Width",
"Breite",
@@ -1168,6 +1308,7 @@ const tPhrase Phrases[] = {
"Leveys",
"Szerokosc",
"Anchura",
+ "Makros",
},
{ "Setup.OSD$Height",
"Höhe",
@@ -1180,6 +1321,7 @@ const tPhrase Phrases[] = {
"Korkeus",
"Wysokosc",
"Altura",
+ "Ipsos",
},
{ "Setup.OSD$Message time (s)",
"Anzeigedauer für Nachrichten (s)",
@@ -1192,6 +1334,7 @@ const tPhrase Phrases[] = {
"Ilmoitusten näkymisaika (s)",
"Czas wyswietlania wiadomosci (s)",
"Duración muestra mensajes (s)",
+ "Xronos endiksis minimaton (d)",
},
{ "Setup.OSD$Channel info position",
"Kanal-Info Position",
@@ -1204,6 +1347,7 @@ const tPhrase Phrases[] = {
"Kanavainfon sijainti",
"Lokalizacja informacji o kanale",
"Posición para información canal",
+ "Thesi Pliroforias kanalion",
},
{ "Setup.OSD$Info on channel switch",
"Info beim Kanalwechsel",
@@ -1216,6 +1360,7 @@ const tPhrase Phrases[] = {
"Näytä kanavainfo",
"Informacja przy zmianie kanalu",
"Información para cambio de canal",
+ "Plirofories stin alagi kanaliou",
},
{ "Setup.OSD$Scroll pages",
"Seitenweise scrollen",
@@ -1228,6 +1373,7 @@ const tPhrase Phrases[] = {
"Valikkojen rullaus",
"Przesuwac stronami",
"Desplazar página entera",
+ "Scroll selidas",
},
{ "Setup.OSD$Sort timers",
"Timer sortieren",
@@ -1240,6 +1386,7 @@ const tPhrase Phrases[] = {
"Järjestä ajastimet",
"Sortowanie timerow",
"Ordenar timer",
+ "Organosi programmatismenon",
},
{ "Setup.OSD$Recording directories",
"Aufnahmeverzeichnisse",
@@ -1252,6 +1399,7 @@ const tPhrase Phrases[] = {
"Nauhoitushakemistot",
"Wykaz nagran",
"Directorios para grabación",
+ "Fakeli egrafon",
},
{ "Setup.EPG$EPG scan timeout (h)",
"Zeit bis EPG Scan (h)",
@@ -1264,6 +1412,7 @@ const tPhrase Phrases[] = {
"Ohjelmatied. odotusaika (h)",
"Czas do skanu EPG (h)",
"Tiempo hasta exploración EPG (h)",
+ "Xronos mexri sarosi EPG se Ores",
},
{ "Setup.EPG$EPG bugfix level",
"EPG Fehlerbereinigung",
@@ -1276,6 +1425,7 @@ const tPhrase Phrases[] = {
"EPG Bugfix Level",
"Poziom bledow EPG",
"Nivel para arreglar EPG",
+ "EPG Bugfix Vathmos",
},
{ "Setup.EPG$Set system time",
"Systemzeit stellen",
@@ -1288,6 +1438,7 @@ const tPhrase Phrases[] = {
"Vastaanota kellonaika",
"Ustawianie czasu",
"Ajustar reloj de sistema",
+ "Sintonismos Oras ipologosti",
},
{ "Setup.EPG$Use time from transponder",
"Transponder für Systemzeit",
@@ -1300,6 +1451,7 @@ const tPhrase Phrases[] = {
"Vastaanota kellonaika lähettimeltä",
"Transponder do ustawiania czasu",
"Transponder para reloj de sistema",
+ "Transponder gia sintonismo tis oras",
},
{ "Setup.DVB$Primary DVB interface",
"Primäres DVB Interface",
@@ -1312,6 +1464,7 @@ const tPhrase Phrases[] = {
"Ensisij. vast.otin",
"Pierwotny interfejs DVB",
"Primer interface DVB",
+ "Protevon DVB karta",
},
{ "Setup.DVB$Video format",
"Video Format",
@@ -1324,6 +1477,7 @@ const tPhrase Phrases[] = {
"Kuvamuoto",
"Format telewizyjny",
"Formato Vídeo",
+ "Video Format",
},
{ "Setup.LNB$SLOF (MHz)",
"SLOF (MHz)",
@@ -1336,6 +1490,7 @@ const tPhrase Phrases[] = {
"SLOF (MHz)",
"SLOF (MHz)",
"SLOF (MHz)",
+ "SLOF (MHz)",
},
{ "Setup.LNB$Low LNB frequency (MHz)",
"Untere LNB-Frequenz (MHz)",
@@ -1348,6 +1503,7 @@ const tPhrase Phrases[] = {
"LO LNB taajuus (MHz)",
"Dolna czestotliwosc LNB (MHz)",
"Frecuencia baja LNB (MHz)",
+ "Kato LNB-Sixnotita (MHz)",
},
{ "Setup.LNB$High LNB frequency (MHz)",
"Obere LNB-Frequenz (MHz)",
@@ -1360,6 +1516,7 @@ const tPhrase Phrases[] = {
"HI LNB taajuus (MHz)",
"Gorna czestotliwosc LNB (MHz)",
"Frecuencia alta LNB (MHz)",
+ "Ano LNB-Sixnotita (MHz)",
},
{ "Setup.LNB$Use DiSEqC",
"DiSEqC benutzen",
@@ -1372,6 +1529,7 @@ const tPhrase Phrases[] = {
"Käytä DiSEqC",
"Uzywac DiSEqC",
"Utilizar DiSEqC",
+ "Energopiisi DiSEqC",
},
{ "Setup.CICAM$CICAM DVB",
"CICAM DVB",
@@ -1384,6 +1542,7 @@ const tPhrase Phrases[] = {
"CICAM DVB",
"CICAM DVB",
"CICAM DVB",
+ "CICAM DVB",
},
{ "Setup.Recording$Margin at start (min)",
"Zeitpuffer bei Anfang (min)",
@@ -1396,6 +1555,7 @@ const tPhrase Phrases[] = {
"Aloitusmarginaali (min)",
"Poczatkowy czas buforowy (min)",
"Comenzar grabación antes (min)",
+ "Prosthetos xronos prin arxi (lepta)",
},
{ "Setup.Recording$Margin at stop (min)",
"Zeitpuffer bei Ende (min)",
@@ -1408,6 +1568,7 @@ const tPhrase Phrases[] = {
"Lopetusmarginaali (min)",
"Koncowy czas buforowy (min)",
"Cortar grabación después (min)",
+ "Prosthetos xronos sto telos (lepta)",
},
{ "Setup.Recording$Primary limit",
"Primär-Limit",
@@ -1420,6 +1581,7 @@ const tPhrase Phrases[] = {
"PrimaryLimit",
"Pierwotny limit",
"L'mite primario",
+ "Protevon limit",
},
{ "Setup.Recording$Default priority",
"Default Priorität",
@@ -1432,6 +1594,7 @@ const tPhrase Phrases[] = {
"Oletusprioriteetti",
"Priorytet pierwotny",
"Prioridad predefinida",
+ "Protereotita",
},
{ "Setup.Recording$Default lifetime (d)",
"Default Lebensdauer (d)",
@@ -1444,6 +1607,7 @@ const tPhrase Phrases[] = {
"Oletus voimassaoloaika (d)",
"Pierwotna trwalosc (d)",
"Duración predefinida",
+ "Xronos zois",
},
{ "Setup.Recording$Use episode name",
"Episodenname verwenden",
@@ -1456,6 +1620,7 @@ const tPhrase Phrases[] = {
"Käytä jakson nimeä",
"Czy uzywac nazwe epizodu",
"Utilizar nombre de episodo",
+ "Xrisimopiisi onomatos episodiou",
},
{ "Setup.Recording$Mark instant recording",
"Direktaufzeichnung markieren",
@@ -1468,6 +1633,7 @@ const tPhrase Phrases[] = {
"Merkitse välitön nauh.",
"Zaznaczyc natychm. nagranie",
"Marcar grabaciones instantáneas",
+ "Markarisma apevthias egrafis",
},
{ "Setup.Recording$Name instant recording",
"Direktaufzeichnung benennen",
@@ -1480,6 +1646,20 @@ const tPhrase Phrases[] = {
"Nimeä välitön nauh.",
"Nazwac natychm. nagranie",
"Nombrar grabaciones instantáneas",
+ "eponomasi apevthias egrafis",
+ },
+ { "Setup.Recording$Instant rec. time (min)",
+ "Dauer der Direktaufzeichnung (min)",
+ "",//TODO
+ "",//TODO
+ "",//TODO
+ "",//TODO
+ "",//TODO
+ "",//TODO
+ "",//TODO
+ "",//TODO
+ "",//TODO
+ "",//TODO
},
{ "Setup.Recording$Record Dolby Digital",
"Dolby Digital Ton aufzeichnen",
@@ -1492,6 +1672,7 @@ const tPhrase Phrases[] = {
"Dolby Digital nauhoitus",
"Nagrywac Dolby Digital",
"Grabar sonido Dolby Digital",
+ "Egrafi tou Dolby Digital ixou",
},
{ "Setup.Recording$Max. video file size (MB)",
"Max. Video Dateigröße (MB)",
@@ -1504,6 +1685,7 @@ const tPhrase Phrases[] = {
"Maksimi tiedoston koko (MB)",
"Maks. wielkosc pliku (MB)",
"Tamaño máx. ficheros (MB)",
+ "Megisto megethos arxeiou (MB)",
},
{ "Setup.Recording$Split edited files",
"Editierte Dateien aufteilen",
@@ -1516,6 +1698,7 @@ const tPhrase Phrases[] = {
"Paloittele muokatut",
"Dzielic montowane pliki",
"Quebrar ficheros",
+ "Diamelisma epeksergasm. arxeion",
},
{ "Setup.Replay$Multi speed mode",
"MultiSpeed Modus",
@@ -1528,6 +1711,7 @@ const tPhrase Phrases[] = {
"Moninopeustila",
"Tryb wielopredkosciowy",
"Modo multi-velocidad",
+ "Multispeed modus",
},
{ "Setup.Replay$Show replay mode",
"Wiedergabestatus anzeigen",
@@ -1540,6 +1724,7 @@ const tPhrase Phrases[] = {
"Näytä toiston tila",
"Wyswietlac status odtwarzania",
"Mostrar modo de replay",
+ "Endiksi status anametadosis",
},
{ "Setup.Miscellaneous$Min. event timeout (min)",
"Mindest Event Pause (min)",
@@ -1552,6 +1737,7 @@ const tPhrase Phrases[] = {
"Minimi tapahtuman odotus (min)",
"Min. czas do nast. akcji (Event) (min)",
"Tiempo mínimo pausa (min)",
+ "Elaxistos Xronos paremvolis (lepta)",
},
{ "Setup.Miscellaneous$Min. user inactivity (min)",
"Mindest Benutzer-Inaktivität (min)",
@@ -1564,18 +1750,20 @@ const tPhrase Phrases[] = {
"Minimi käyttäjän odotus (min)",
"Min. brak aktywnosci uzytkownika (min)",
"Tiempo mínimo inactividad (min)",
- },
- { "Setup.Miscellaneous$SVDRP timeout (min)",
- "SVDRP Timeout (min)",
- "SVDRP Timeout (min)",
- "Timeout SVDRP (min)",
- "SVDRP Timeout (min)",
- "Timeout SVDRP (min)",
- "Temps maxi SVDRP (min)",
- "Ubrukt SVDRP-levetid (min)",
- "SVDRP odotusaika (min)",
- "Min. brak aktywnosci SVDRP (min)",
- "SVDRP interrupción (min)",
+ "Elaxistos xronos mi xrisis (lepta)",
+ },
+ { "Setup.Miscellaneous$SVDRP timeout (s)",
+ "SVDRP Timeout (s)",
+ "SVDRP Timeout (s)",
+ "Timeout SVDRP (s)",
+ "SVDRP Timeout (s)",
+ "Timeout SVDRP (s)",
+ "Temps maxi SVDRP (s)",
+ "Ubrukt SVDRP-levetid (s)",
+ "SVDRP odotusaika (s)",
+ "Min. brak aktywnosci SVDRP (s)",
+ "SVDRP interrupción (s)",
+ "SVDRP Timeout (d)",
},
// The days of the week:
{ "MTWTFSS",
@@ -1589,6 +1777,7 @@ const tPhrase Phrases[] = {
"MTKTPLS",
"PWSCPSN",
"LMMJVSD",
+ "DTTPPSK",
},
{ "MonTueWedThuFriSatSun", // must all be 3 letters!
"MonDieMitDonFreSamSon",
@@ -1601,6 +1790,21 @@ const tPhrase Phrases[] = {
"MaaTiiKesTorPerLauSun",
"PonWtoSroCzwPiaSobNie",
"LunMarMieJueVieSabDom",
+ "DevTriTetPemParSavKir",
+ },
+ // The allowed characters in strings:
+ { " abcdefghijklmnopqrstuvwxyz0123456789-.#~",
+ " aäbcdefghijklmnoöpqrstuüvwxyz0123456789-.#~",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ " aábcdeéfghiíjklmnñoópqrstuúvwxyz0123456789-.#~",
+ "",// TODO
},
// Learning keys:
{ "Learning Remote Control Keys",
@@ -1614,6 +1818,7 @@ const tPhrase Phrases[] = {
"Kaukosäätimen näppäinten opettelu",
"Nauka kodu pilota",
"Aprendiendo teclas del telemando",
+ "Ekmathisi Remote Control",
},
{ "Phase 1: Detecting RC code type",
"Phase 1: FB Code feststellen",
@@ -1626,6 +1831,7 @@ const tPhrase Phrases[] = {
"Vaihe 1: Lähetystavan selvittäminen",
"Faza 1: Detekcja typu kodu",
"Fase 1: Detectando tipo de receptor",
+ "Phasi 1: Dilosi RC Code",
},
{ "Press any key on the RC unit",
"Eine Taste auf der FB drücken",
@@ -1638,6 +1844,7 @@ const tPhrase Phrases[] = {
"Paina mitä tahansa kaukosäätimen näppäintä",
"Nacisnac klawisz pilota",
"Pulse una tecla en el telemando",
+ "Pata ena pliktro sto RC",
},
{ "RC code detected!",
"FB Code erkannt!",
@@ -1650,6 +1857,7 @@ const tPhrase Phrases[] = {
"Näppäinpainallus vastaanotettu!",
"Kod pilota zostal poznany!",
"¡Código detectado!",
+ "Evresi RC Code!",
},
{ "Do not press any key...",
"Keine Taste drücken...",
@@ -1662,6 +1870,7 @@ const tPhrase Phrases[] = {
"Älä paina mitään näppäintä...",
"Nie naciskac klawiszy...",
"No pulse tecla...",
+ "Min patas Pliktra...",
},
{ "Phase 2: Learning specific key codes",
"Phase 2: Einzelne Tastencodes lernen",
@@ -1674,6 +1883,7 @@ const tPhrase Phrases[] = {
"Vaihe 2: Näppäinkoodien opettelu",
"Faza 2: Nauka pojedynczych klawiszy",
"Fase 2: Aprendiendo códigos específicos",
+ "Fasi 2: Ekmathisi memonomenon kodikon pliktron",
},
{ "Press key for '%s'",
"Taste für '%s' drücken",
@@ -1686,6 +1896,7 @@ const tPhrase Phrases[] = {
"Paina näppäintä toiminnolle '%s'",
"Nacisnac klawisz dla '%s'",
"Pulsar tecla para '%s'",
+ "Pata to pliktro gia '%s'",
},
{ "Press 'Up' to confirm",
"'Auf' drücken zum Bestätigen",
@@ -1698,6 +1909,7 @@ const tPhrase Phrases[] = {
"Paina 'Ylös' hyväksyäksesi",
"Nacisnac 'Gora' do potwierdzenia",
"Pulse 'Arriba' para confirmar",
+ "Pata 'pano' gia apodoxi",
},
{ "Press 'Down' to continue",
"'Ab' drücken zum Weitermachen",
@@ -1710,6 +1922,7 @@ const tPhrase Phrases[] = {
"Paina 'Alas' jatkaaksesi",
"Nacisnac 'Dol' zeby kontynuowac",
"Pulse 'Abajo' para confirmar",
+ "Pata 'kato' gia sinexia",
},
{ "(press 'Up' to go back)",
"('Auf' drücken um zurückzugehen)",
@@ -1722,6 +1935,7 @@ const tPhrase Phrases[] = {
"(paina 'Ylös' palataksesi takaisin)",
"(Nacisnac 'Gora' cofa)",
"(Pulse 'Arriba' para retornar)",
+ "(Pata 'pano' gia na pas piso)",
},
{ "(press 'Down' to end key definition)",
"('Ab' drücken zum Beenden)",
@@ -1734,6 +1948,7 @@ const tPhrase Phrases[] = {
"(paina 'Alas' lopettaaksesi näppäinten opettelun)",
"(Nacisnac 'Dol' by zakonczyc)",
"(Pulse 'Abajo' para terminar programación teclas)",
+ "(Pata 'Kato' gia termatismo)",
},
{ "Phase 3: Saving key codes",
"Phase 3: Codes abspeichern",
@@ -1746,6 +1961,7 @@ const tPhrase Phrases[] = {
"Vaihe 3: Näppäinkoodien tallettaminen",
"Faza 3: Zapamietac Kod",
"Fase 3: Guardar códigos de teclas",
+ "Fasi 3: Apothikevsi kodikon",
},
{ "Press 'Up' to save, 'Down' to cancel",
"'Auf' speichert, 'Ab' bricht ab",
@@ -1758,6 +1974,7 @@ const tPhrase Phrases[] = {
"Paina 'Ylös' tallettaaksesi ja 'Alas' peruuttaaksesi",
"'Gora' zapamietuje, 'Dol' przerywa",
"Pulse 'Arriba' para guarder, 'Abajo' para anular",
+ "'kato' apothikevsi, 'Pano' akirosi",
},
// Key names:
{ "Up",
@@ -1771,6 +1988,7 @@ const tPhrase Phrases[] = {
"Ylös",
"Gora",
"Arriba",
+ "Pano",
},
{ "Down",
"Ab",
@@ -1783,6 +2001,7 @@ const tPhrase Phrases[] = {
"Alas",
"Dol",
"Abajo",
+ "Kato",
},
{ "Menu",
"Menü",
@@ -1795,6 +2014,7 @@ const tPhrase Phrases[] = {
"Valikko",
"Menu",
"Menu",
+ "Menou",
},
{ "Ok",
"Ok",
@@ -1807,6 +2027,7 @@ const tPhrase Phrases[] = {
"Ok",
"Ok",
"Ok",
+ "Ok",
},
{ "Back",
"Zurück",
@@ -1819,6 +2040,7 @@ const tPhrase Phrases[] = {
"Takaisin",
"Wstecz",
"Retornar",
+ "Piso",
},
{ "Left",
"Links",
@@ -1831,6 +2053,7 @@ const tPhrase Phrases[] = {
"Vasemmalle",
"Lewo",
"Izquierda",
+ "Aristera",
},
{ "Right",
"Rechts",
@@ -1843,6 +2066,7 @@ const tPhrase Phrases[] = {
"Oikealle",
"Prawo",
"Derecha",
+ "Deksia",
},
{ "Red",
"Rot",
@@ -1855,6 +2079,7 @@ const tPhrase Phrases[] = {
"Punainen",
"Czerwony",
"Rojo",
+ "Kokino",
},
{ "Green",
"Grün",
@@ -1867,6 +2092,7 @@ const tPhrase Phrases[] = {
"Vihreä",
"Zielony",
"Verde",
+ "Prasino",
},
{ "Yellow",
"Gelb",
@@ -1879,6 +2105,7 @@ const tPhrase Phrases[] = {
"Keltainen",
"Zolty",
"Amarillo",
+ "Kitrino",
},
{ "Blue",
"Blau",
@@ -1891,6 +2118,7 @@ const tPhrase Phrases[] = {
"Sininen",
"Niebieski",
"Azul",
+ "Mple",
},
{ "Power",
"Ausschalten",
@@ -1903,6 +2131,7 @@ const tPhrase Phrases[] = {
"Virtakytkin",
"Wylaczyc",
"Corriente",
+ "Klisimo",
},
{ "Volume+",
"Lautstärke+",
@@ -1915,6 +2144,7 @@ const tPhrase Phrases[] = {
"Äänenvoimakkuus+",
"Glosnej",
"Volumen+",
+ "Entasi+",
},
{ "Volume-",
"Lautstärke-",
@@ -1927,6 +2157,7 @@ const tPhrase Phrases[] = {
"Äänenvoimakkuus-",
"Ciszej",
"Volumen-",
+ "Entasi-",
},
{ "Mute",
"Stumm",
@@ -1939,6 +2170,7 @@ const tPhrase Phrases[] = {
"Äänen vaimennus",
"Cisza",
"Mudo",
+ "Mougko",
},
// Miscellaneous:
{ "yes",
@@ -1952,6 +2184,7 @@ const tPhrase Phrases[] = {
"kyllä",
"tak",
"sí",
+ "nai",
},
{ "no",
"nein",
@@ -1964,6 +2197,7 @@ const tPhrase Phrases[] = {
"ei",
"nie",
"no",
+ "oxi",
},
{ "top",
"oben",
@@ -1976,6 +2210,7 @@ const tPhrase Phrases[] = {
"ylä",
"gora",
"parte sup.",
+ "pano",
},
{ "bottom",
"unten",
@@ -1988,6 +2223,7 @@ const tPhrase Phrases[] = {
"ala",
"dol",
"fondo",
+ "kato",
},
{ "Disk",
"Disk",
@@ -2000,6 +2236,7 @@ const tPhrase Phrases[] = {
"Disk",
"Disk",
"Disco",
+ "Disk",
},
{ "free",
"frei",
@@ -2012,6 +2249,7 @@ const tPhrase Phrases[] = {
"vapaa",
"pozostalo",
"libre",
+ "akoma",
},
{ "Jump: ", // note the trailing blank
"Springen: ",
@@ -2024,6 +2262,7 @@ const tPhrase Phrases[] = {
"Hyppää: ",
"Skok: ",
"Saltar: ",
+ "Pidima: ",
},
{ "Volume ", // note the trailing blank
"Lautstärke ",
@@ -2036,6 +2275,7 @@ const tPhrase Phrases[] = {
"Äänenvoimakkuus ",
"Glosnosc ",
"Volumen ",
+ "Entasi ",
},
{ " Stop replaying", // note the leading blank!
" Wiedergabe beenden",
@@ -2048,6 +2288,7 @@ const tPhrase Phrases[] = {
" Pysäytä toisto",
" Zatrzymac odtwarzanie",
" Parar reprodución",
+ " Telos anametadosis",
},
{ " Stop recording ", // note the leading and trailing blanks!
" Aufzeichnung beenden ",
@@ -2060,6 +2301,7 @@ const tPhrase Phrases[] = {
" Pysäytä nauhoitus ",
" Zatrzymac nagrywanie ",
" Parar grabación ",
+ " Telos egrafis ",
},
{ " Cancel editing", // note the leading blank!
" Schneiden abbrechen",
@@ -2070,8 +2312,9 @@ const tPhrase Phrases[] = {
" Annuler le montage",
" Avbryt redigering",
" Peruuta muokkaus",
- " Przerwac montaz ",
- " Anular modificación ",
+ " Przerwac montaz",
+ " Anular modificación",
+ " Diakopi kopsimatos",
},
{ "Switching primary DVB...",
"Primäres Interface wird umgeschaltet...",
@@ -2080,10 +2323,11 @@ const tPhrase Phrases[] = {
"Eerste DVB-kaart wordt omgeschakeld...",
"A mudar interface DVB primário...",
"Changement de carte DVB primaire...",
- "Bytter første DVB-enhet..."
+ "Bytter første DVB-enhet...",
"Vaihdetaan ensisijainen vastaanotin...",
"Pierwszy interfejs DVB przelacza...",
"Cambio interface primario...",
+ "I protevon DVB Karta alazi...",
},
{ "Up/Dn for new location - OK to move",
"Auf/Ab für neue Position - dann OK",
@@ -2096,6 +2340,7 @@ const tPhrase Phrases[] = {
"Ylös/Alas = liiku, OK = siirrä",
"Gora/Dol na nowa pozycje - Ok zmienia",
"Arriba/Abajo para nuevo lugar - OK para mover",
+ "Pano/Kato gia nea thesi. meta OK",
},
{ "Editing process started",
"Schnitt gestartet",
@@ -2108,6 +2353,7 @@ const tPhrase Phrases[] = {
"Muokkaus aloitettu",
"Uruchomiony proces montazu",
"Proceso modificación iniciado",
+ "Arxi kopsimatos",
},
{ "Editing process finished",
"Schnitt beendet",
@@ -2120,6 +2366,7 @@ const tPhrase Phrases[] = {
"Muokkaus lopetettu",
"Proces montazu zakonczony",
"Proceso modificacion terminado",
+ "To kopsimo termatistike",
},
{ "Editing process failed!",
"Schnitt gescheitert!",
@@ -2132,6 +2379,7 @@ const tPhrase Phrases[] = {
"Muokkaus epäonnistui!",
"Bledny proces montazu!",
"Modificación ha fallado!",
+ "Kopsimo apetixe!",
},
{ "scanning recordings...",
"Aufzeichnungen werden durchsucht...",
@@ -2144,27 +2392,103 @@ const tPhrase Phrases[] = {
"haetaan nauhoituksia...",
"Skan nagran...",
"buscando grabaciones...",
+ "Ginete sarosi egrafon...",
+ },
+ { "This plugin has no setup parameters!",
+ "Dieses Plugin hat keine Setup-Parameter!",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
},
{ NULL }
};
-const char *tr(const char *s)
+// --- cI18nEntry ------------------------------------------------------------
+
+class cI18nEntry : public cListObject {
+private:
+ const tI18nPhrase *phrases;
+ const char *plugin;
+public:
+ cI18nEntry(const tI18nPhrase * const Phrases, const char *Plugin);
+ const tI18nPhrase *Phrases(void) { return phrases; }
+ const char *Plugin(void) { return plugin; }
+ };
+
+cI18nEntry::cI18nEntry(const tI18nPhrase * const Phrases, const char *Plugin)
+{
+ phrases = Phrases;
+ plugin = Plugin;
+}
+
+// --- cI18nList -------------------------------------------------------------
+
+class cI18nList : public cList<cI18nEntry> {
+public:
+ cI18nEntry *Get(const char *Plugin);
+ const tI18nPhrase *GetPhrases(const char *Plugin);
+ };
+
+cI18nEntry *cI18nList::Get(const char *Plugin)
+{
+ if (Plugin) {
+ for (cI18nEntry *p = First(); p; p = Next(p)) {
+ if (strcmp(p->Plugin(), Plugin) == 0)
+ return p;
+ }
+ }
+ return NULL;
+}
+
+const tI18nPhrase *cI18nList::GetPhrases(const char *Plugin)
+{
+ cI18nEntry *p = Get(Plugin);
+ return p ? p->Phrases() : NULL;
+}
+
+cI18nList I18nList;
+
+// ---
+
+void I18nRegister(const tI18nPhrase * const Phrases, const char *Plugin)
+{
+ cI18nEntry *p = I18nList.Get(Plugin);
+ if (p)
+ I18nList.Del(p);
+ if (Phrases)
+ I18nList.Add(new cI18nEntry(Phrases, Plugin));
+}
+
+const char *I18nTranslate(const char *s, const char *Plugin)
{
if (Setup.OSDLanguage) {
- for (const tPhrase *p = Phrases; **p; p++) {
- if (strcmp(s, **p) == 0) {
- const char *t = (*p)[Setup.OSDLanguage];
- if (t && *t)
- return t;
- }
+ const tI18nPhrase *p = Plugin ? I18nList.GetPhrases(Plugin) : Phrases;
+ if (!p)
+ p = Phrases;
+ for (int i = ((p == Phrases) ? 1 : 2); i--; ) {
+ for (; **p; p++) {
+ if (strcmp(s, **p) == 0) {
+ const char *t = (*p)[Setup.OSDLanguage];
+ if (t && *t)
+ return t;
+ }
+ }
+ p = Phrases;
}
- esyslog(LOG_ERR, "no translation found for '%s' in language %d (%s)\n", s, Setup.OSDLanguage, Phrases[0][Setup.OSDLanguage]);
+ esyslog(LOG_ERR, "%s%sno translation found for '%s' in language %d (%s)\n", Plugin ? Plugin : "", Plugin ? ": " : "", s, Setup.OSDLanguage, Phrases[0][Setup.OSDLanguage]);
}
const char *p = strchr(s, '$');
return p ? p + 1 : s;
}
-const char * const * Languages(void)
+const char * const * I18nLanguages(void)
{
return &Phrases[0][0];
}
diff --git a/i18n.h b/i18n.h
index c94241a..68fe736 100644
--- a/i18n.h
+++ b/i18n.h
@@ -4,16 +4,28 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: i18n.h 1.1 2000/11/11 09:27:25 kls Exp $
+ * $Id: i18n.h 1.2 2002/05/05 13:42:31 kls Exp $
*/
#ifndef __I18N_H
#define __I18N_H
-extern const int NumLanguages;
+#include <stdio.h>
-const char *tr(const char *s);
+const int I18nNumLanguages = 12;
-const char * const * Languages(void);
+typedef const char *tI18nPhrase[I18nNumLanguages];
+
+void I18nRegister(const tI18nPhrase * const Phrases, const char *Plugin);
+
+const char *I18nTranslate(const char *s, const char *Plugin = NULL);
+
+const char * const * I18nLanguages(void);
+
+#ifdef PLUGIN_NAME_I18N
+#define tr(s) I18nTranslate(s, PLUGIN_NAME_I18N)
+#else
+#define tr(s) I18nTranslate(s)
+#endif
#endif //__I18N_H
diff --git a/interface.h b/interface.h
index dbfa1bc..914a383 100644
--- a/interface.h
+++ b/interface.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: interface.h 1.24 2001/09/01 15:14:50 kls Exp $
+ * $Id: interface.h 1.25 2002/04/19 13:17:15 kls Exp $
*/
#ifndef __INTERFACE_H
@@ -46,6 +46,7 @@ public:
void SetBitmap(int x, int y, const cBitmap &Bitmap);
void Flush(void);
void SetCols(int *c);
+ const int *GetCols(void) { return cols; }
eDvbFont SetFont(eDvbFont Font);
char *WrapText(const char *Text, int Width, int *Height);
void Write(int x, int y, const char *s, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground);
diff --git a/menu.c b/menu.c
index bc3aeb6..ef75819 100644
--- a/menu.c
+++ b/menu.c
@@ -4,10 +4,11 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: menu.c 1.182 2002/04/06 09:41:59 kls Exp $
+ * $Id: menu.c 1.190 2002/05/09 10:13:47 kls Exp $
*/
#include "menu.h"
+#include <ctype.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
@@ -15,134 +16,19 @@
#include "config.h"
#include "eit.h"
#include "i18n.h"
+#include "menuitems.h"
+#include "plugin.h"
#include "videodir.h"
#define MENUTIMEOUT 120 // seconds
#define MAXWAIT4EPGINFO 10 // seconds
#define MODETIMEOUT 3 // seconds
-#define CHNUMWIDTH (Channels.Count() > 999 ? 5 : 4) // there are people with more than 999 channels...
-
-const char *FileNameChars = " aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789-.#~^";
-
-// --- cMenuEditItem ---------------------------------------------------------
-
-class cMenuEditItem : public cOsdItem {
-private:
- const char *name;
- const char *value;
-public:
- cMenuEditItem(const char *Name);
- ~cMenuEditItem();
- void SetValue(const char *Value);
- };
-
-cMenuEditItem::cMenuEditItem(const char *Name)
-{
- name = strdup(Name);
- value = NULL;
-}
-
-cMenuEditItem::~cMenuEditItem()
-{
- delete name;
- delete value;
-}
-
-void cMenuEditItem::SetValue(const char *Value)
-{
- delete value;
- value = strdup(Value);
- char *buffer = NULL;
- asprintf(&buffer, "%s:\t%s", name, value);
- SetText(buffer, false);
- Display();
-}
-
-// --- cMenuEditIntItem ------------------------------------------------------
-
-class cMenuEditIntItem : public cMenuEditItem {
-protected:
- int *value;
- int min, max;
- virtual void Set(void);
-public:
- cMenuEditIntItem(const char *Name, int *Value, int Min = 0, int Max = INT_MAX);
- virtual eOSState ProcessKey(eKeys Key);
- };
-
-cMenuEditIntItem::cMenuEditIntItem(const char *Name, int *Value, int Min, int Max)
-:cMenuEditItem(Name)
-{
- value = Value;
- min = Min;
- max = Max;
- Set();
-}
-
-void cMenuEditIntItem::Set(void)
-{
- char buf[16];
- snprintf(buf, sizeof(buf), "%d", *value);
- SetValue(buf);
-}
+#define MAXINSTANTRECTIME (24 * 60 - 1) // 23:59 hours
-eOSState cMenuEditIntItem::ProcessKey(eKeys Key)
-{
- eOSState state = cMenuEditItem::ProcessKey(Key);
-
- if (state == osUnknown) {
- int newValue;
- if (k0 <= Key && Key <= k9) {
- if (fresh) {
- *value = 0;
- fresh = false;
- }
- newValue = *value * 10 + (Key - k0);
- }
- else if (NORMALKEY(Key) == kLeft) { // TODO might want to increase the delta if repeated quickly?
- newValue = *value - 1;
- fresh = true;
- }
- else if (NORMALKEY(Key) == kRight) {
- newValue = *value + 1;
- fresh = true;
- }
- else
- return state;
- if ((!fresh || min <= newValue) && newValue <= max) {
- *value = newValue;
- Set();
- }
- state = osContinue;
- }
- return state;
-}
-
-// --- cMenuEditBoolItem -----------------------------------------------------
-
-class cMenuEditBoolItem : public cMenuEditIntItem {
-protected:
- const char *falseString, *trueString;
- virtual void Set(void);
-public:
- cMenuEditBoolItem(const char *Name, int *Value, const char *FalseString = NULL, const char *TrueString = NULL);
- };
+#define CHNUMWIDTH (Channels.Count() > 999 ? 5 : 4) // there are people with more than 999 channels...
-cMenuEditBoolItem::cMenuEditBoolItem(const char *Name, int *Value, const char *FalseString, const char *TrueString)
-:cMenuEditIntItem(Name, Value, 0, 1)
-{
- falseString = FalseString ? FalseString : tr("no");
- trueString = TrueString ? TrueString : tr("yes");
- Set();
-}
-
-void cMenuEditBoolItem::Set(void)
-{
- char buf[16];
- snprintf(buf, sizeof(buf), "%s", *value ? trueString : falseString);
- SetValue(buf);
-}
+const char *FileNameChars = " abcdefghijklmnopqrstuvwxyz0123456789-.#~";
// --- cMenuEditChanItem -----------------------------------------------------
@@ -448,186 +334,6 @@ eOSState cMenuEditTimeItem::ProcessKey(eKeys Key)
return state;
}
-// --- cMenuEditChrItem ------------------------------------------------------
-
-class cMenuEditChrItem : public cMenuEditItem {
-private:
- char *value;
- const char *allowed;
- const char *current;
- virtual void Set(void);
-public:
- cMenuEditChrItem(const char *Name, char *Value, const char *Allowed);
- ~cMenuEditChrItem();
- virtual eOSState ProcessKey(eKeys Key);
- };
-
-cMenuEditChrItem::cMenuEditChrItem(const char *Name, char *Value, const char *Allowed)
-:cMenuEditItem(Name)
-{
- value = Value;
- allowed = strdup(Allowed);
- current = strchr(allowed, *Value);
- if (!current)
- current = allowed;
- Set();
-}
-
-cMenuEditChrItem::~cMenuEditChrItem()
-{
- delete allowed;
-}
-
-void cMenuEditChrItem::Set(void)
-{
- char buf[2];
- snprintf(buf, sizeof(buf), "%c", *value);
- SetValue(buf);
-}
-
-eOSState cMenuEditChrItem::ProcessKey(eKeys Key)
-{
- eOSState state = cMenuEditItem::ProcessKey(Key);
-
- if (state == osUnknown) {
- if (NORMALKEY(Key) == kLeft) {
- if (current > allowed)
- current--;
- }
- else if (NORMALKEY(Key) == kRight) {
- if (*(current + 1))
- current++;
- }
- else
- return state;
- *value = *current;
- Set();
- state = osContinue;
- }
- return state;
-}
-
-// --- cMenuEditStrItem ------------------------------------------------------
-
-class cMenuEditStrItem : public cMenuEditItem {
-private:
- char *value;
- int length;
- const char *allowed;
- int pos;
- virtual void Set(void);
- char Inc(char c, bool Up);
-public:
- cMenuEditStrItem(const char *Name, char *Value, int Length, const char *Allowed);
- ~cMenuEditStrItem();
- virtual eOSState ProcessKey(eKeys Key);
- };
-
-cMenuEditStrItem::cMenuEditStrItem(const char *Name, char *Value, int Length, const char *Allowed)
-:cMenuEditItem(Name)
-{
- value = Value;
- length = Length;
- allowed = strdup(Allowed);
- pos = -1;
- Set();
-}
-
-cMenuEditStrItem::~cMenuEditStrItem()
-{
- delete allowed;
-}
-
-void cMenuEditStrItem::Set(void)
-{
- char buf[1000];
- if (pos >= 0) {
- strncpy(buf, value, pos);
- const char *s = value[pos] != '^' ? value + pos + 1 : "";
- snprintf(buf + pos, sizeof(buf) - pos - 2, "[%c]%s", *(value + pos), s);
- SetValue(buf);
- }
- else
- SetValue(value);
-}
-
-char cMenuEditStrItem::Inc(char c, bool Up)
-{
- const char *p = strchr(allowed, c);
- if (!p)
- p = allowed;
- if (Up) {
- if (!*++p)
- p = allowed;
- }
- else if (--p < allowed)
- p = allowed + strlen(allowed) - 1;
- return *p;
-}
-
-eOSState cMenuEditStrItem::ProcessKey(eKeys Key)
-{
- switch (Key) {
- case kLeft|k_Repeat:
- case kLeft: if (pos > 0) {
- if (value[pos] == '^')
- value[pos] = 0;
- pos--;
- }
- break;
- case kRight|k_Repeat:
- case kRight: if (pos < length && value[pos] != '^' && (pos < int(strlen(value) - 1) || value[pos] != ' ')) {
- if (++pos >= int(strlen(value))) {
- value[pos] = ' ';
- value[pos + 1] = 0;
- }
- }
- break;
- case kUp|k_Repeat:
- case kUp:
- case kDown|k_Repeat:
- case kDown: if (pos >= 0)
- value[pos] = Inc(value[pos], NORMALKEY(Key) == kUp);
- else
- return cMenuEditItem::ProcessKey(Key);
- break;
- case kOk: if (pos >= 0) {
- if (value[pos] == '^')
- value[pos] = 0;
- pos = -1;
- stripspace(value);
- break;
- }
- // run into default
- default: return cMenuEditItem::ProcessKey(Key);
- }
- Set();
- return osContinue;
-}
-
-// --- cMenuEditStraItem -----------------------------------------------------
-
-class cMenuEditStraItem : public cMenuEditIntItem {
-private:
- const char * const *strings;
-protected:
- virtual void Set(void);
-public:
- cMenuEditStraItem(const char *Name, int *Value, int NumStrings, const char * const *Strings);
- };
-
-cMenuEditStraItem::cMenuEditStraItem(const char *Name, int *Value, int NumStrings, const char * const *Strings)
-:cMenuEditIntItem(Name, Value, 0, NumStrings - 1)
-{
- strings = Strings;
- Set();
-}
-
-void cMenuEditStraItem::Set(void)
-{
- SetValue(strings[*value]);
-}
-
// --- cMenuEditCaItem -------------------------------------------------------
class cMenuEditCaItem : public cMenuEditIntItem {
@@ -699,7 +405,7 @@ cMenuEditChannel::cMenuEditChannel(int Index)
channel = Channels.Get(Index);
if (channel) {
data = *channel;
- Add(new cMenuEditStrItem( tr("Name"), data.name, sizeof(data.name), FileNameChars));
+ Add(new cMenuEditStrItem( tr("Name"), data.name, sizeof(data.name), tr(FileNameChars)));
Add(new cMenuEditIntItem( tr("Frequency"), &data.frequency));
Add(new cMenuEditChrItem( tr("Polarization"), &data.polarization, "hv"));
Add(new cMenuEditIntItem( tr("DiSEqC"), &data.diseqc, 0, 10)); //TODO exact limits???
@@ -919,116 +625,6 @@ eOSState cMenuChannels::ProcessKey(eKeys Key)
return state;
}
-// --- cMenuTextItem ---------------------------------------------------------
-
-class cMenuTextItem : public cOsdItem {
-private:
- char *text;
- int x, y, w, h, lines, offset;
- eDvbColor fgColor, bgColor;
- eDvbFont font;
-public:
- cMenuTextItem(const char *Text, int X, int Y, int W, int H = -1, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground, eDvbFont Font = fontOsd);
- ~cMenuTextItem();
- int Height(void) { return h; }
- void Clear(void);
- virtual void Display(int Offset = -1, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground);
- bool CanScrollUp(void) { return offset > 0; }
- bool CanScrollDown(void) { return h + offset < lines; }
- void ScrollUp(bool Page);
- void ScrollDown(bool Page);
- virtual eOSState ProcessKey(eKeys Key);
- };
-
-cMenuTextItem::cMenuTextItem(const char *Text, int X, int Y, int W, int H, eDvbColor FgColor, eDvbColor BgColor, eDvbFont Font)
-{
- x = X;
- y = Y;
- w = W;
- h = H;
- fgColor = FgColor;
- bgColor = BgColor;
- font = Font;
- offset = 0;
- eDvbFont oldFont = Interface->SetFont(font);
- text = Interface->WrapText(Text, w - 1, &lines);
- Interface->SetFont(oldFont);
- if (h < 0)
- h = lines;
-}
-
-cMenuTextItem::~cMenuTextItem()
-{
- delete text;
-}
-
-void cMenuTextItem::Clear(void)
-{
- Interface->Fill(x, y, w, h, bgColor);
-}
-
-void cMenuTextItem::Display(int Offset, eDvbColor FgColor, eDvbColor BgColor)
-{
- int l = 0;
- char *t = text;
- eDvbFont oldFont = Interface->SetFont(font);
- while (*t) {
- char *n = strchr(t, '\n');
- if (l >= offset) {
- if (n)
- *n = 0;
- Interface->Write(x, y + l - offset, t, fgColor, bgColor);
- if (n)
- *n = '\n';
- else
- break;
- }
- if (!n)
- break;
- t = n + 1;
- if (++l >= h + offset)
- break;
- }
- Interface->SetFont(oldFont);
- // scroll indicators use inverted color scheme!
- if (CanScrollUp()) Interface->Write(x + w - 1, y, "^", bgColor, fgColor);
- if (CanScrollDown()) Interface->Write(x + w - 1, y + h - 1, "v", bgColor, fgColor);
-}
-
-void cMenuTextItem::ScrollUp(bool Page)
-{
- if (CanScrollUp()) {
- Clear();
- offset = max(offset - (Page ? h : 1), 0);
- Display();
- }
-}
-
-void cMenuTextItem::ScrollDown(bool Page)
-{
- if (CanScrollDown()) {
- Clear();
- offset = min(offset + (Page ? h : 1), lines - h);
- Display();
- }
-}
-
-eOSState cMenuTextItem::ProcessKey(eKeys Key)
-{
- switch (Key) {
- case kLeft|k_Repeat:
- case kLeft:
- case kUp|k_Repeat:
- case kUp: ScrollUp(NORMALKEY(Key) == kLeft); break;
- case kRight|k_Repeat:
- case kRight:
- case kDown|k_Repeat:
- case kDown: ScrollDown(NORMALKEY(Key) == kRight); break;
- default: return osUnknown;
- }
- return osContinue;
-}
-
// --- cMenuText -------------------------------------------------------------
class cMenuText : public cOsdMenu {
@@ -1086,7 +682,7 @@ cMenuEditTimer::cMenuEditTimer(int Index, bool New)
//TODO VPS???
Add(new cMenuEditIntItem( tr("Priority"), &data.priority, 0, MAXPRIORITY));
Add(new cMenuEditIntItem( tr("Lifetime"), &data.lifetime, 0, MAXLIFETIME));
- Add(new cMenuEditStrItem( tr("File"), data.file, sizeof(data.file), FileNameChars));
+ Add(new cMenuEditStrItem( tr("File"), data.file, sizeof(data.file), tr(FileNameChars)));
SetFirstDayItem();
}
}
@@ -1929,60 +1525,6 @@ eOSState cMenuRecordings::ProcessKey(eKeys Key)
return state;
}
-// --- cMenuSetupPage --------------------------------------------------------
-
-class cMenuSetupPage : public cOsdMenu {
-protected:
- cSetup data;
- int osdLanguage;
- void SetupTitle(const char *s);
- virtual void Set(void) = 0;
-public:
- cMenuSetupPage(void);
- virtual eOSState ProcessKey(eKeys Key);
- };
-
-cMenuSetupPage::cMenuSetupPage(void)
-:cOsdMenu("", 33)
-{
- data = Setup;
- osdLanguage = Setup.OSDLanguage;
-}
-
-void cMenuSetupPage::SetupTitle(const char *s)
-{
- char buf[40]; // can't call tr() for more than one string at a time!
- char *q = buf + snprintf(buf, sizeof(buf), "%s - ", tr("Setup"));
- snprintf(q, sizeof(buf) - strlen(buf), "%s", tr(s));
- SetTitle(buf);
-}
-
-eOSState cMenuSetupPage::ProcessKey(eKeys Key)
-{
- eOSState state = cOsdMenu::ProcessKey(Key);
-
- if (state == osUnknown) {
- switch (Key) {
- case kOk: state = (Setup.PrimaryDVB != data.PrimaryDVB) ? osSwitchDvb : osBack;
- cDvbApi::PrimaryDvbApi->SetVideoFormat(data.VideoFormat ? VIDEO_FORMAT_16_9 : VIDEO_FORMAT_4_3);
- Setup = data;
- Setup.Save();
- cDvbApi::SetCaCaps();
- break;
- default: break;
- }
- }
- if (data.OSDLanguage != osdLanguage) {
- int OriginalOSDLanguage = Setup.OSDLanguage;
- Setup.OSDLanguage = data.OSDLanguage;
- Set();
- Display();
- osdLanguage = data.OSDLanguage;
- Setup.OSDLanguage = OriginalOSDLanguage;
- }
- return state;
-}
-
// --- cMenuSetupOSD ---------------------------------------------------------
class cMenuSetupOSD : public cMenuSetupPage {
@@ -1996,7 +1538,7 @@ void cMenuSetupOSD::Set(void)
{
Clear();
SetupTitle("OSD");
- Add(new cMenuEditStraItem(tr("Setup.OSD$Language"), &data.OSDLanguage, NumLanguages, Languages()));
+ Add(new cMenuEditStraItem(tr("Setup.OSD$Language"), &data.OSDLanguage, I18nNumLanguages, I18nLanguages()));
Add(new cMenuEditIntItem( tr("Setup.OSD$Width"), &data.OSDwidth, MINOSDWIDTH, MAXOSDWIDTH));
Add(new cMenuEditIntItem( tr("Setup.OSD$Height"), &data.OSDheight, MINOSDHEIGHT, MAXOSDHEIGHT));
Add(new cMenuEditIntItem( tr("Setup.OSD$Message time (s)"), &data.OSDMessageTime, 1, 60));
@@ -2104,7 +1646,8 @@ void cMenuSetupRecord::Set(void)
Add(new cMenuEditIntItem( tr("Setup.Recording$Default lifetime (d)"), &data.DefaultLifetime, 0, MAXLIFETIME));
Add(new cMenuEditBoolItem(tr("Setup.Recording$Use episode name"), &data.UseSubtitle));
Add(new cMenuEditBoolItem(tr("Setup.Recording$Mark instant recording"), &data.MarkInstantRecord));
- Add(new cMenuEditStrItem( tr("Setup.Recording$Name instant recording"), data.NameInstantRecord, sizeof(data.NameInstantRecord), FileNameChars));
+ Add(new cMenuEditStrItem( tr("Setup.Recording$Name instant recording"), data.NameInstantRecord, sizeof(data.NameInstantRecord), tr(FileNameChars)));
+ Add(new cMenuEditIntItem( tr("Setup.Recording$Instant rec. time (min)"), &data.InstantRecordTime, 1, MAXINSTANTRECTIME));
Add(new cMenuEditBoolItem(tr("Setup.Recording$Record Dolby Digital"), &data.RecordDolbyDigital));
Add(new cMenuEditIntItem( tr("Setup.Recording$Max. video file size (MB)"), &data.MaxVideoFileSize, MINVIDEOFILESIZE, MAXVIDEOFILESIZE));
Add(new cMenuEditBoolItem(tr("Setup.Recording$Split edited files"), &data.SplitEditedFiles));
@@ -2142,7 +1685,76 @@ void cMenuSetupMisc::Set(void)
SetupTitle("Miscellaneous");
Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. event timeout (min)"), &data.MinEventTimeout));
Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. user inactivity (min)"), &data.MinUserInactivity));
- Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$SVDRP timeout (min)"), &data.SVDRPTimeout));
+ Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$SVDRP timeout (s)"), &data.SVDRPTimeout));
+}
+
+// --- cMenuSetupPluginItem --------------------------------------------------
+
+class cMenuSetupPluginItem : public cOsdItem {
+private:
+ int pluginIndex;
+public:
+ cMenuSetupPluginItem(const char *Name, int Index);
+ int PluginIndex(void) { return pluginIndex; }
+ };
+
+cMenuSetupPluginItem::cMenuSetupPluginItem(const char *Name, int Index)
+:cOsdItem(Name)
+{
+ pluginIndex = Index;
+}
+
+// --- cMenuSetupPlugins -----------------------------------------------------
+
+class cMenuSetupPlugins : public cMenuSetupPage {
+private:
+ virtual void Set(void);
+public:
+ cMenuSetupPlugins(void) { Set(); }
+ virtual eOSState ProcessKey(eKeys Key);
+ };
+
+void cMenuSetupPlugins::Set(void)
+{
+ Clear();
+ SetupTitle("Plugins");
+ SetHasHotkeys();
+ for (int i = 0; ; i++) {
+ cPlugin *p = cPluginManager::GetPlugin(i);
+ if (p) {
+ char *buffer = NULL;
+ asprintf(&buffer, "%s (%s) - %s", p->Name(), p->Version(), p->Description());
+ Add(new cMenuSetupPluginItem(hk(buffer), i));
+ delete buffer;
+ }
+ else
+ break;
+ }
+}
+
+eOSState cMenuSetupPlugins::ProcessKey(eKeys Key)
+{
+ eOSState state = cOsdMenu::ProcessKey(Key); // not cMenuSetupPage::ProcessKey()!
+
+ if (state == osUnknown) {
+ switch (Key) {
+ case kOk: {
+ cMenuSetupPluginItem *item = (cMenuSetupPluginItem *)Get(Current());
+ if (item) {
+ cPlugin *p = cPluginManager::GetPlugin(item->PluginIndex());
+ if (p) {
+ cOsdMenu *menu = p->SetupMenu();
+ if (menu)
+ return AddSubMenu(menu);
+ Interface->Info(tr("This plugin has no setup parameters!"));
+ }
+ }
+ }
+ break;
+ default: break;
+ }
+ }
+ return state;
}
// --- cMenuSetup ------------------------------------------------------------
@@ -2165,7 +1777,9 @@ cMenuSetup::cMenuSetup(void)
void cMenuSetup::Set(void)
{
Clear();
- SetTitle(tr("Setup"));
+ char buffer[64];
+ snprintf(buffer, sizeof(buffer), "%s - VDR %s", tr("Setup"), VDRVERSION);
+ SetTitle(buffer);
SetHasHotkeys();
Add(new cOsdItem(hk(tr("OSD")), osUser1));
Add(new cOsdItem(hk(tr("EPG")), osUser2));
@@ -2175,7 +1789,9 @@ void cMenuSetup::Set(void)
Add(new cOsdItem(hk(tr("Recording")), osUser6));
Add(new cOsdItem(hk(tr("Replay")), osUser7));
Add(new cOsdItem(hk(tr("Miscellaneous")), osUser8));
- Add(new cOsdItem(hk(tr("Restart")), osUser9));
+ if (cPluginManager::HasPlugins())
+ Add(new cOsdItem(hk(tr("Plugins")), osUser9));
+ Add(new cOsdItem(hk(tr("Restart")), osUser10));
}
eOSState cMenuSetup::Restart(void)
@@ -2201,7 +1817,8 @@ eOSState cMenuSetup::ProcessKey(eKeys Key)
case osUser6: return AddSubMenu(new cMenuSetupRecord);
case osUser7: return AddSubMenu(new cMenuSetupReplay);
case osUser8: return AddSubMenu(new cMenuSetupMisc);
- case osUser9: return Restart();
+ case osUser9: return AddSubMenu(new cMenuSetupPlugins);
+ case osUser10: return Restart();
default: ;
}
if (Setup.OSDLanguage != osdLanguage) {
@@ -2264,6 +1881,22 @@ eOSState cMenuCommands::ProcessKey(eKeys Key)
return state;
}
+// --- cMenuPluginItem -------------------------------------------------------
+
+class cMenuPluginItem : public cOsdItem {
+private:
+ int pluginIndex;
+public:
+ cMenuPluginItem(const char *Name, int Index);
+ int PluginIndex(void) { return pluginIndex; }
+ };
+
+cMenuPluginItem::cMenuPluginItem(const char *Name, int Index)
+:cOsdItem(Name, osPlugin)
+{
+ pluginIndex = Index;
+}
+
// --- cMenuMain -------------------------------------------------------------
#define STOP_RECORDING tr(" Stop recording ")
@@ -2308,6 +1941,22 @@ void cMenuMain::Set(void)
Add(new cOsdItem(hk(tr("Channels")), osChannels));
Add(new cOsdItem(hk(tr("Timers")), osTimers));
Add(new cOsdItem(hk(tr("Recordings")), osRecordings));
+
+ // Plugins:
+
+ for (int i = 0; ; i++) {
+ cPlugin *p = cPluginManager::GetPlugin(i);
+ if (p) {
+ const char *item = p->MainMenuEntry();
+ if (item)
+ Add(new cMenuPluginItem(hk(item), i));
+ }
+ else
+ break;
+ }
+
+ // More basic menu items:
+
Add(new cOsdItem(hk(tr("Setup")), osSetup));
if (Commands.Count())
Add(new cOsdItem(hk(tr("Commands")), osCommands));
@@ -2375,6 +2024,19 @@ eOSState cMenuMain::ProcessKey(eKeys Key)
return osEnd;
}
break;
+ case osPlugin: {
+ cMenuPluginItem *item = (cMenuPluginItem *)Get(Current());
+ if (item) {
+ cPlugin *p = cPluginManager::GetPlugin(item->PluginIndex());
+ if (p) {
+ cOsdMenu *menu = p->MainMenuAction();
+ if (menu)
+ return AddSubMenu(menu);
+ }
+ }
+ state = osEnd;
+ }
+ break;
default: switch (Key) {
case kMenu: state = osEnd; break;
case kRed: if (!HasSubMenu())
@@ -3185,6 +2847,7 @@ void cReplayControl::TimeSearch(void)
else
return;
}
+ timeoutShow = 0;
TimeSearchDisplay();
timeSearchActive = true;
}
@@ -3287,7 +2950,7 @@ eOSState cReplayControl::ProcessKey(eKeys Key)
}
else if (modeOnly)
ShowMode();
- else
+ else
shown = ShowProgress(!shown) || shown;
}
bool DisplayedFrames = displayFrames;
diff --git a/menu.h b/menu.h
index 8893016..a0e0851 100644
--- a/menu.h
+++ b/menu.h
@@ -4,11 +4,11 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: menu.h 1.41 2002/03/31 13:53:23 kls Exp $
+ * $Id: menu.h 1.42 2002/04/13 15:31:41 kls Exp $
*/
-#ifndef _MENU_H
-#define _MENU_H
+#ifndef __MENU_H
+#define __MENU_H
#include "dvbapi.h"
#include "osd.h"
@@ -142,4 +142,4 @@ public:
static void ClearLastReplayed(const char *FileName);
};
-#endif //_MENU_H
+#endif //__MENU_H
diff --git a/menuitems.c b/menuitems.c
new file mode 100644
index 0000000..d09f5b7
--- /dev/null
+++ b/menuitems.c
@@ -0,0 +1,476 @@
+/*
+ * menuitems.c: General purpose menu items
+ *
+ * See the main source file 'vdr.c' for copyright information and
+ * how to reach the author.
+ *
+ * $Id: menuitems.c 1.1 2002/05/09 10:10:12 kls Exp $
+ */
+
+#include "menuitems.h"
+#include <ctype.h>
+#include "i18n.h"
+
+// --- cMenuEditItem ---------------------------------------------------------
+
+cMenuEditItem::cMenuEditItem(const char *Name)
+{
+ name = strdup(Name);
+ value = NULL;
+}
+
+cMenuEditItem::~cMenuEditItem()
+{
+ delete name;
+ delete value;
+}
+
+void cMenuEditItem::SetValue(const char *Value)
+{
+ delete value;
+ value = strdup(Value);
+ char *buffer = NULL;
+ asprintf(&buffer, "%s:\t%s", name, value);
+ SetText(buffer, false);
+ Display();
+}
+
+// --- cMenuEditIntItem ------------------------------------------------------
+
+cMenuEditIntItem::cMenuEditIntItem(const char *Name, int *Value, int Min, int Max)
+:cMenuEditItem(Name)
+{
+ value = Value;
+ min = Min;
+ max = Max;
+ Set();
+}
+
+void cMenuEditIntItem::Set(void)
+{
+ char buf[16];
+ snprintf(buf, sizeof(buf), "%d", *value);
+ SetValue(buf);
+}
+
+eOSState cMenuEditIntItem::ProcessKey(eKeys Key)
+{
+ eOSState state = cMenuEditItem::ProcessKey(Key);
+
+ if (state == osUnknown) {
+ int newValue;
+ if (k0 <= Key && Key <= k9) {
+ if (fresh) {
+ *value = 0;
+ fresh = false;
+ }
+ newValue = *value * 10 + (Key - k0);
+ }
+ else if (NORMALKEY(Key) == kLeft) { // TODO might want to increase the delta if repeated quickly?
+ newValue = *value - 1;
+ fresh = true;
+ }
+ else if (NORMALKEY(Key) == kRight) {
+ newValue = *value + 1;
+ fresh = true;
+ }
+ else
+ return state;
+ if ((!fresh || min <= newValue) && newValue <= max) {
+ *value = newValue;
+ Set();
+ }
+ state = osContinue;
+ }
+ return state;
+}
+
+// --- cMenuEditBoolItem -----------------------------------------------------
+
+cMenuEditBoolItem::cMenuEditBoolItem(const char *Name, int *Value, const char *FalseString, const char *TrueString)
+:cMenuEditIntItem(Name, Value, 0, 1)
+{
+ falseString = FalseString ? FalseString : tr("no");
+ trueString = TrueString ? TrueString : tr("yes");
+ Set();
+}
+
+void cMenuEditBoolItem::Set(void)
+{
+ char buf[16];
+ snprintf(buf, sizeof(buf), "%s", *value ? trueString : falseString);
+ SetValue(buf);
+}
+
+// --- cMenuEditChrItem ------------------------------------------------------
+
+cMenuEditChrItem::cMenuEditChrItem(const char *Name, char *Value, const char *Allowed)
+:cMenuEditItem(Name)
+{
+ value = Value;
+ allowed = strdup(Allowed);
+ current = strchr(allowed, *Value);
+ if (!current)
+ current = allowed;
+ Set();
+}
+
+cMenuEditChrItem::~cMenuEditChrItem()
+{
+ delete allowed;
+}
+
+void cMenuEditChrItem::Set(void)
+{
+ char buf[2];
+ snprintf(buf, sizeof(buf), "%c", *value);
+ SetValue(buf);
+}
+
+eOSState cMenuEditChrItem::ProcessKey(eKeys Key)
+{
+ eOSState state = cMenuEditItem::ProcessKey(Key);
+
+ if (state == osUnknown) {
+ if (NORMALKEY(Key) == kLeft) {
+ if (current > allowed)
+ current--;
+ }
+ else if (NORMALKEY(Key) == kRight) {
+ if (*(current + 1))
+ current++;
+ }
+ else
+ return state;
+ *value = *current;
+ Set();
+ state = osContinue;
+ }
+ return state;
+}
+
+// --- cMenuEditStrItem ------------------------------------------------------
+
+cMenuEditStrItem::cMenuEditStrItem(const char *Name, char *Value, int Length, const char *Allowed)
+:cMenuEditItem(Name)
+{
+ value = Value;
+ length = Length;
+ allowed = strdup(Allowed);
+ pos = -1;
+ insert = uppercase = false;
+ newchar = true;
+ Set();
+}
+
+cMenuEditStrItem::~cMenuEditStrItem()
+{
+ delete allowed;
+}
+
+void cMenuEditStrItem::SetHelpKeys(void)
+{
+ if (pos >= 0)
+ Interface->Help(tr("ABC/abc"), tr(insert ? "Overwrite" : "Insert"), tr("Delete"));
+ else
+ Interface->Help(NULL);
+}
+
+void cMenuEditStrItem::Set(void)
+{
+ char buf[1000];
+ const char *fmt = insert && newchar ? "[]%c%s" : "[%c]%s";
+
+ if (pos >= 0) {
+ strncpy(buf, value, pos);
+ snprintf(buf + pos, sizeof(buf) - pos - 2, fmt, *(value + pos), value + pos + 1);
+ int width = Interface->Width() - Interface->GetCols()[0];
+ if (cDvbApi::PrimaryDvbApi->WidthInCells(buf) <= width) {
+ // the whole buffer fits on the screen
+ SetValue(buf);
+ return;
+ }
+ width *= cDvbApi::PrimaryDvbApi->CellWidth();
+ width -= cDvbApi::PrimaryDvbApi->Width('>'); // assuming '<' and '>' have the same with
+ int w = 0;
+ int i = 0;
+ int l = strlen(buf);
+ while (i < l && w <= width)
+ w += cDvbApi::PrimaryDvbApi->Width(buf[i++]);
+ if (i >= pos + 4) {
+ // the cursor fits on the screen
+ buf[i - 1] = '>';
+ buf[i] = 0;
+ SetValue(buf);
+ return;
+ }
+ // the cursor doesn't fit on the screen
+ w = 0;
+ if (buf[i = pos + 3]) {
+ buf[i] = '>';
+ buf[i + 1] = 0;
+ }
+ else
+ i--;
+ while (i >= 0 && w <= width)
+ w += cDvbApi::PrimaryDvbApi->Width(buf[i--]);
+ buf[++i] = '<';
+ SetValue(buf + i);
+ }
+ else
+ SetValue(value);
+}
+
+char cMenuEditStrItem::Inc(char c, bool Up)
+{
+ const char *p = strchr(allowed, c);
+ if (!p)
+ p = allowed;
+ if (Up) {
+ if (!*++p)
+ p = allowed;
+ }
+ else if (--p < allowed)
+ p = allowed + strlen(allowed) - 1;
+ return *p;
+}
+
+eOSState cMenuEditStrItem::ProcessKey(eKeys Key)
+{
+ switch (Key) {
+ case kRed: // Switch between upper- and lowercase characters
+ if (pos >= 0 && (!insert || !newchar)) {
+ uppercase = !uppercase;
+ value[pos] = uppercase ? toupper(value[pos]) : tolower(value[pos]);
+ }
+ break;
+ case kGreen: // Toggle insert/overwrite modes
+ if (pos >= 0) {
+ insert = !insert;
+ newchar = true;
+ }
+ SetHelpKeys();
+ break;
+ case kYellow|k_Repeat:
+ case kYellow: // Remove the character at current position; in insert mode it is the character to the right of cursor
+ if (pos >= 0) {
+ if (strlen(value) > 1) {
+ memmove(value + pos, value + pos + 1, strlen(value) - pos);
+ // reduce position, if we removed the last character
+ if (pos == int(strlen(value)))
+ pos--;
+ }
+ else if (strlen(value) == 1)
+ value[0] = ' '; // This is the last character in the string, replace it with a blank
+ if (isalpha(value[pos]))
+ uppercase = isupper(value[pos]);
+ newchar = true;
+ }
+ break;
+ case kLeft|k_Repeat:
+ case kLeft: if (pos > 0) {
+ if (!insert || newchar)
+ pos--;
+ newchar = true;
+ }
+ if (!insert && isalpha(value[pos]))
+ uppercase = isupper(value[pos]);
+ break;
+ case kRight|k_Repeat:
+ case kRight: if (pos < length && pos < int(strlen(value)) ) {
+ if (++pos >= int(strlen(value))) {
+ if (pos >= 2 && value[pos - 1] == ' ' && value[pos - 2] == ' ')
+ pos--; // allow only two blanks at the end
+ else {
+ value[pos] = ' ';
+ value[pos + 1] = 0;
+ }
+ }
+ }
+ newchar = true;
+ if (!insert && isalpha(value[pos]))
+ uppercase = isupper(value[pos]);
+ if (pos == 0)
+ SetHelpKeys();
+ break;
+ case kUp|k_Repeat:
+ case kUp:
+ case kDown|k_Repeat:
+ case kDown: if (pos >= 0) {
+ if (insert && newchar) {
+ // create a new character in insert mode
+ if (int(strlen(value)) < length) {
+ memmove(value + pos + 1, value + pos, strlen(value) - pos + 1);
+ value[pos] = ' ';
+ }
+ }
+ if (uppercase)
+ value[pos] = toupper(Inc(tolower(value[pos]), NORMALKEY(Key) == kUp));
+ else
+ value[pos] = Inc( value[pos], NORMALKEY(Key) == kUp);
+ newchar = false;
+ }
+ else
+ return cMenuEditItem::ProcessKey(Key);
+ break;
+ case kOk: if (pos >= 0) {
+ pos = -1;
+ newchar = true;
+ stripspace(value);
+ SetHelpKeys();
+ break;
+ }
+ // run into default
+ default: return cMenuEditItem::ProcessKey(Key);
+ }
+ Set();
+ return osContinue;
+}
+
+// --- cMenuEditStraItem -----------------------------------------------------
+
+cMenuEditStraItem::cMenuEditStraItem(const char *Name, int *Value, int NumStrings, const char * const *Strings)
+:cMenuEditIntItem(Name, Value, 0, NumStrings - 1)
+{
+ strings = Strings;
+ Set();
+}
+
+void cMenuEditStraItem::Set(void)
+{
+ SetValue(strings[*value]);
+}
+
+// --- cMenuTextItem ---------------------------------------------------------
+
+cMenuTextItem::cMenuTextItem(const char *Text, int X, int Y, int W, int H, eDvbColor FgColor, eDvbColor BgColor, eDvbFont Font)
+{
+ x = X;
+ y = Y;
+ w = W;
+ h = H;
+ fgColor = FgColor;
+ bgColor = BgColor;
+ font = Font;
+ offset = 0;
+ eDvbFont oldFont = Interface->SetFont(font);
+ text = Interface->WrapText(Text, w - 1, &lines);
+ Interface->SetFont(oldFont);
+ if (h < 0)
+ h = lines;
+}
+
+cMenuTextItem::~cMenuTextItem()
+{
+ delete text;
+}
+
+void cMenuTextItem::Clear(void)
+{
+ Interface->Fill(x, y, w, h, bgColor);
+}
+
+void cMenuTextItem::Display(int Offset, eDvbColor FgColor, eDvbColor BgColor)
+{
+ int l = 0;
+ char *t = text;
+ eDvbFont oldFont = Interface->SetFont(font);
+ while (*t) {
+ char *n = strchr(t, '\n');
+ if (l >= offset) {
+ if (n)
+ *n = 0;
+ Interface->Write(x, y + l - offset, t, fgColor, bgColor);
+ if (n)
+ *n = '\n';
+ else
+ break;
+ }
+ if (!n)
+ break;
+ t = n + 1;
+ if (++l >= h + offset)
+ break;
+ }
+ Interface->SetFont(oldFont);
+ // scroll indicators use inverted color scheme!
+ if (CanScrollUp()) Interface->Write(x + w - 1, y, "^", bgColor, fgColor);
+ if (CanScrollDown()) Interface->Write(x + w - 1, y + h - 1, "v", bgColor, fgColor);
+}
+
+void cMenuTextItem::ScrollUp(bool Page)
+{
+ if (CanScrollUp()) {
+ Clear();
+ offset = max(offset - (Page ? h : 1), 0);
+ Display();
+ }
+}
+
+void cMenuTextItem::ScrollDown(bool Page)
+{
+ if (CanScrollDown()) {
+ Clear();
+ offset = min(offset + (Page ? h : 1), lines - h);
+ Display();
+ }
+}
+
+eOSState cMenuTextItem::ProcessKey(eKeys Key)
+{
+ switch (Key) {
+ case kLeft|k_Repeat:
+ case kLeft:
+ case kUp|k_Repeat:
+ case kUp: ScrollUp(NORMALKEY(Key) == kLeft); break;
+ case kRight|k_Repeat:
+ case kRight:
+ case kDown|k_Repeat:
+ case kDown: ScrollDown(NORMALKEY(Key) == kRight); break;
+ default: return osUnknown;
+ }
+ return osContinue;
+}
+
+// --- cMenuSetupPage --------------------------------------------------------
+
+cMenuSetupPage::cMenuSetupPage(void)
+:cOsdMenu("", 33)
+{
+ data = Setup;
+ osdLanguage = Setup.OSDLanguage;
+}
+
+void cMenuSetupPage::SetupTitle(const char *s)
+{
+ char buf[40]; // can't call tr() for more than one string at a time!
+ char *q = buf + snprintf(buf, sizeof(buf), "%s - ", tr("Setup"));
+ snprintf(q, sizeof(buf) - strlen(buf), "%s", tr(s));
+ SetTitle(buf);
+}
+
+eOSState cMenuSetupPage::ProcessKey(eKeys Key)
+{
+ eOSState state = cOsdMenu::ProcessKey(Key);
+
+ if (state == osUnknown) {
+ switch (Key) {
+ case kOk: state = (Setup.PrimaryDVB != data.PrimaryDVB) ? osSwitchDvb : osBack;
+ cDvbApi::PrimaryDvbApi->SetVideoFormat(data.VideoFormat ? VIDEO_FORMAT_16_9 : VIDEO_FORMAT_4_3);
+ Setup = data;
+ Setup.Save();
+ cDvbApi::SetCaCaps();
+ break;
+ default: break;
+ }
+ }
+ if (data.OSDLanguage != osdLanguage) {
+ int OriginalOSDLanguage = Setup.OSDLanguage;
+ Setup.OSDLanguage = data.OSDLanguage;
+ Set();
+ Display();
+ osdLanguage = data.OSDLanguage;
+ Setup.OSDLanguage = OriginalOSDLanguage;
+ }
+ return state;
+}
diff --git a/menuitems.h b/menuitems.h
new file mode 100644
index 0000000..a08a714
--- /dev/null
+++ b/menuitems.h
@@ -0,0 +1,110 @@
+/*
+ * menuitems.h: General purpose menu items
+ *
+ * See the main source file 'vdr.c' for copyright information and
+ * how to reach the author.
+ *
+ * $Id: menuitems.h 1.1 2002/05/09 09:41:06 kls Exp $
+ */
+
+#ifndef __MENUITEMS_H
+#define __MENUITEMS_H
+
+#include "osd.h"
+
+class cMenuEditItem : public cOsdItem {
+private:
+ const char *name;
+ const char *value;
+public:
+ cMenuEditItem(const char *Name);
+ ~cMenuEditItem();
+ void SetValue(const char *Value);
+ };
+
+class cMenuEditIntItem : public cMenuEditItem {
+protected:
+ int *value;
+ int min, max;
+ virtual void Set(void);
+public:
+ cMenuEditIntItem(const char *Name, int *Value, int Min = 0, int Max = INT_MAX);
+ virtual eOSState ProcessKey(eKeys Key);
+ };
+
+class cMenuEditBoolItem : public cMenuEditIntItem {
+protected:
+ const char *falseString, *trueString;
+ virtual void Set(void);
+public:
+ cMenuEditBoolItem(const char *Name, int *Value, const char *FalseString = NULL, const char *TrueString = NULL);
+ };
+
+class cMenuEditChrItem : public cMenuEditItem {
+private:
+ char *value;
+ const char *allowed;
+ const char *current;
+ virtual void Set(void);
+public:
+ cMenuEditChrItem(const char *Name, char *Value, const char *Allowed);
+ ~cMenuEditChrItem();
+ virtual eOSState ProcessKey(eKeys Key);
+ };
+
+class cMenuEditStrItem : public cMenuEditItem {
+private:
+ char *value;
+ int length;
+ const char *allowed;
+ int pos;
+ bool insert, newchar, uppercase;
+ void SetHelpKeys(void);
+ virtual void Set(void);
+ char Inc(char c, bool Up);
+public:
+ cMenuEditStrItem(const char *Name, char *Value, int Length, const char *Allowed);
+ ~cMenuEditStrItem();
+ virtual eOSState ProcessKey(eKeys Key);
+ };
+
+class cMenuEditStraItem : public cMenuEditIntItem {
+private:
+ const char * const *strings;
+protected:
+ virtual void Set(void);
+public:
+ cMenuEditStraItem(const char *Name, int *Value, int NumStrings, const char * const *Strings);
+ };
+
+class cMenuTextItem : public cOsdItem {
+private:
+ char *text;
+ int x, y, w, h, lines, offset;
+ eDvbColor fgColor, bgColor;
+ eDvbFont font;
+public:
+ cMenuTextItem(const char *Text, int X, int Y, int W, int H = -1, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground, eDvbFont Font = fontOsd);
+ ~cMenuTextItem();
+ int Height(void) { return h; }
+ void Clear(void);
+ virtual void Display(int Offset = -1, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground);
+ bool CanScrollUp(void) { return offset > 0; }
+ bool CanScrollDown(void) { return h + offset < lines; }
+ void ScrollUp(bool Page);
+ void ScrollDown(bool Page);
+ virtual eOSState ProcessKey(eKeys Key);
+ };
+
+class cMenuSetupPage : public cOsdMenu {
+protected:
+ cSetup data;
+ int osdLanguage;
+ void SetupTitle(const char *s);
+ virtual void Set(void) = 0;
+public:
+ cMenuSetupPage(void);
+ virtual eOSState ProcessKey(eKeys Key);
+ };
+
+#endif //__MENUITEMS_H
diff --git a/newplugin b/newplugin
new file mode 100755
index 0000000..22d18f4
--- /dev/null
+++ b/newplugin
@@ -0,0 +1,250 @@
+#!/usr/bin/perl -w
+
+# newplugin: Initializing a new plugin source directory
+#
+# Creates a new plugin source directory from which to start implementing
+# a plugin for VDR.
+# See the file PLUGINS.html for detailed instructions on how to
+# write a plugin.
+#
+# Usage: newplugin <name>
+#
+# See the main source file 'vdr.c' for copyright information and
+# how to reach the author.
+#
+# $Id: newplugin 1.1 2002/05/09 15:12:26 kls Exp $
+
+$PLUGIN_NAME = $ARGV[0] || die "Usage: newplugin <name>\n";
+
+die "Please use only lowercase letters and digits in the plugin name\n" if ($PLUGIN_NAME =~ tr/a-z0-9//c);
+
+$PLUGIN_CLASS = ucfirst($PLUGIN_NAME);
+
+$PLUGIN_VERSION = "0.0.1";
+$PLUGIN_DESCRIPTION = "Enter description for '$PLUGIN_NAME' plugin";
+$PLUGIN_MAINENTRY = $PLUGIN_CLASS;
+
+$PLUGINS_SRC = "PLUGINS/SRC";
+
+$README = qq
+{This is a "plugin" for the Video Disk Recorder (VDR).
+
+Written by: Your Name <email\@host.dom>
+
+Project's homepage: URL
+
+Latest version available at: URL
+
+See the file COPYING for license information.
+
+Description:
+};
+
+$HISTORY_TITLE = "VDR Plugin '$PLUGIN_NAME' Revision History";
+$HISTORY_LINE = '-' x length($HISTORY_TITLE);
+$HISTORY_DATE = sprintf("%4d-%02d-%02d", (localtime)[5] + 1900, (localtime)[4] + 1, (localtime)[3]);
+$HISTORY = qq
+{$HISTORY_TITLE
+$HISTORY_LINE
+
+$HISTORY_DATE: Version $PLUGIN_VERSION
+
+- Initial revision.
+};
+
+$MAKEFILE = qq
+{#
+# Makefile for a Video Disk Recorder plugin
+#
+# \$Id\$
+
+# The official name of this plugin.
+# This name will be used in the '-P...' option of VDR to load the plugin.
+# By default the main source file also carries this name.
+#
+PLUGIN = $PLUGIN_NAME
+
+### The version number of this plugin (taken from the main source file):
+
+VERSION = `grep 'static const char \\*VERSION *=' \$(PLUGIN).c | awk '{ print \$\$6 }' | sed -e 's/[";]//g'`
+
+### The directory environment:
+
+DVBDIR = ../../../../DVB/ost/include
+VDRDIR = ../../..
+VDRINC = \$(VDRDIR)/include
+LIBDIR = ../../lib
+TMPDIR = /tmp
+
+### The version number of VDR (taken from VDR's "config.h"):
+
+VDRVERSION = `grep 'define VDRVERSION ' \$(VDRDIR)/config.h | awk '{ print \$\$3 }' | sed -e 's/"//g'`
+
+### The name of the distribution archive:
+
+ARCHIVE = vdr-\$(PLUGIN)-\$(VERSION)
+
+### Includes and Defines (add further entries here):
+
+INCLUDES = -I\$(VDRINC) -I\$(DVBDIR)
+
+DEFINES = -DPLUGIN_NAME_I18N='"\$(PLUGIN)"'
+
+### The object files (add further files here):
+
+OBJS = \$(PLUGIN).o
+
+### The C++ compiler and options:
+
+CXX = g++
+CXXFLAGS = -O2 -Wall -Woverloaded-virtual -m486
+
+### Implicit rules:
+
+%.o: %.c
+ \$(CXX) \$(CXXFLAGS) -c \$(DEFINES) \$(INCLUDES) \$<
+
+# Dependencies:
+
+MAKEDEP = g++ -MM -MG
+DEPFILE = .dependencies
+\$(DEPFILE): Makefile
+ \@\$(MAKEDEP) \$(DEFINES) \$(INCLUDES) \$(OBJS:%.o=%.c) > \$\@
+
+include \$(DEPFILE)
+
+### Targets:
+
+all: libvdr-\$(PLUGIN).so
+
+libvdr-\$(PLUGIN).so: \$(OBJS)
+ \$(CXX) \$(CXXFLAGS) -shared \$(OBJS) -o \$\@
+ \@cp \$\@ \$(LIBDIR)/\$\@.\$(VDRVERSION)
+
+package: clean
+ \@-rm -rf \$(TMPDIR)/\$(ARCHIVE)
+ \@mkdir \$(TMPDIR)/\$(ARCHIVE)
+ \@cp -a * \$(TMPDIR)/\$(ARCHIVE)
+ \@tar czf \$(ARCHIVE).tgz -C \$(TMPDIR) \$(ARCHIVE)
+ \@-rm -rf \$(TMPDIR)/\$(ARCHIVE)
+ \@echo Distribution archive created as \$(ARCHIVE).tgz
+
+clean:
+ \@-rm -f \$(OBJS) \$(DEPFILE) *.so *.tgz core* *~
+};
+
+$MAIN = qq
+{/*
+ * $PLUGIN_NAME.c: A plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ * \$Id\$
+ */
+
+#include <vdr/plugin.h>
+
+static const char *VERSION = "$PLUGIN_VERSION";
+static const char *DESCRIPTION = "$PLUGIN_DESCRIPTION";
+static const char *MAINMENUENTRY = "$PLUGIN_MAINENTRY";
+
+class cPlugin$PLUGIN_CLASS : public cPlugin {
+private:
+ // Add any member variables or functions you may need here.
+public:
+ cPlugin$PLUGIN_CLASS(void);
+ virtual ~cPlugin$PLUGIN_CLASS();
+ virtual const char *Version(void) { return VERSION; }
+ virtual const char *Description(void) { return DESCRIPTION; }
+ virtual const char *CommandLineHelp(void);
+ virtual bool ProcessArgs(int argc, char *argv[]);
+ virtual void Start(void);
+ virtual const char *MainMenuEntry(void) { return MAINMENUENTRY; }
+ virtual cOsdMenu *MainMenuAction(void);
+ virtual cMenuSetupPage *SetupMenu(void);
+ virtual bool SetupParse(const char *Name, const char *Value);
+ };
+
+cPlugin${PLUGIN_CLASS}::cPlugin$PLUGIN_CLASS(void)
+{
+ // Initialize any member varaiables here.
+ // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL
+ // VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT!
+}
+
+cPlugin${PLUGIN_CLASS}::~cPlugin$PLUGIN_CLASS()
+{
+ // Clean up after yourself!
+}
+
+const char *cPlugin${PLUGIN_CLASS}::CommandLineHelp(void)
+{
+ // Return a string that describes all known command line options.
+ return NULL;
+}
+
+bool cPlugin${PLUGIN_CLASS}::ProcessArgs(int argc, char *argv[])
+{
+ // Implement command line argument processing here if applicable.
+ return true;
+}
+
+void cPlugin${PLUGIN_CLASS}::Start(void)
+{
+ // Start any background activities the plugin shall perform.
+}
+
+cOsdMenu *cPlugin${PLUGIN_CLASS}::MainMenuAction(void)
+{
+ // Perform the action when selected from the main VDR menu.
+ return NULL;
+}
+
+cMenuSetupPage *cPlugin${PLUGIN_CLASS}::SetupMenu(void)
+{
+ // Return a setup menu in case the plugin supports one.
+ return NULL;
+}
+
+bool cPlugin${PLUGIN_CLASS}::SetupParse(const char *Name, const char *Value)
+{
+ // Parse your own setup parameters and store their values.
+ return false;
+}
+
+VDRPLUGINCREATOR(cPlugin$PLUGIN_CLASS); // Don't touch this!
+};
+
+$PLUGINDIR = "$PLUGINS_SRC/$PLUGIN_NAME";
+
+die "The directory $PLUGINS_SRC doesn't exist!\n" unless (-d "$PLUGINS_SRC");
+die "A plugin named '$PLUGIN_NAME' already exists in $PLUGINS_SRC!\n" if (-e "$PLUGINDIR");
+mkdir("$PLUGINDIR") || die "$!";
+
+CreateFile("README", $README);
+CreateFile("HISTORY", $HISTORY);
+CreateFile("Makefile", $MAKEFILE);
+CreateFile("$PLUGIN_NAME.c", $MAIN);
+`cp COPYING "$PLUGINDIR"` if (-e "COPYING");
+
+print qq{
+The new plugin source directory has been created in "$PLUGINDIR".
+
+The next steps you should perform now are:
+
+* edit the file "README" to adjust it to your specific implementation
+* fill in the code skeleton in "$PLUGIN_NAME.c" to implement your plugin function
+* add further source files if necessary
+* adapt the "Makefile" if necessary
+* do "make plugins" from the VDR source directory to build your plugin
+
+};
+
+sub CreateFile
+{
+ my ($Name, $Content) = @_;
+ open(FILE, ">$PLUGINDIR/$Name") || die "$Name: $!\n";
+ print FILE $Content;
+ close(FILE);
+}
+
diff --git a/osd.c b/osd.c
index 56ba9b5..1116784 100644
--- a/osd.c
+++ b/osd.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: osd.c 1.23 2002/03/29 16:34:03 kls Exp $
+ * $Id: osd.c 1.24 2002/05/01 11:53:24 kls Exp $
*/
#include "osd.h"
@@ -105,12 +105,13 @@ cOsdMenu::~cOsdMenu()
const char *cOsdMenu::hk(const char *s)
{
- static char buffer[32];
+ static char buffer[64];
if (s && hasHotkeys) {
if (digit == 0 && '1' <= *s && *s <= '9' && *(s + 1) == ' ')
- digit = 10; // prevents automatic hotkeys - input already has them
- if (digit < 9) {
- snprintf(buffer, sizeof(buffer), " %d %s", ++digit, s);
+ digit = -1; // prevents automatic hotkeys - input already has them
+ if (digit >= 0) {
+ digit++;
+ snprintf(buffer, sizeof(buffer), " %c %s", (digit < 10) ? '0' + digit : ' ' , s);
s = buffer;
}
}
diff --git a/osd.h b/osd.h
index 8e82586..6f05329 100644
--- a/osd.h
+++ b/osd.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: osd.h 1.27 2002/03/10 16:18:11 kls Exp $
+ * $Id: osd.h 1.28 2002/05/01 11:17:42 kls Exp $
*/
#ifndef __OSD_H
@@ -23,6 +23,7 @@ enum eOSState { osUnknown,
osChannels,
osTimers,
osRecordings,
+ osPlugin,
osSetup,
osCommands,
osRecord,
@@ -43,6 +44,7 @@ enum eOSState { osUnknown,
osUser7,
osUser8,
osUser9,
+ osUser10,
};
class cOsdItem : public cListObject {
diff --git a/plugin.c b/plugin.c
new file mode 100644
index 0000000..ecae317
--- /dev/null
+++ b/plugin.c
@@ -0,0 +1,319 @@
+/*
+ * plugin.c: The VDR plugin interface
+ *
+ * See the main source file 'vdr.c' for copyright information and
+ * how to reach the author.
+ *
+ * $Id: plugin.c 1.1 2002/05/09 16:26:56 kls Exp $
+ */
+
+#include "plugin.h"
+#include <ctype.h>
+#include <dirent.h>
+#include <dlfcn.h>
+#include "config.h"
+
+#define LIBVDR_PREFIX "libvdr-"
+#define SO_INDICATOR ".so."
+
+#define MAXPLUGINARGS 1024
+
+// --- cPlugin ---------------------------------------------------------------
+
+cPlugin::cPlugin(void)
+{
+ name = NULL;
+}
+
+cPlugin::~cPlugin()
+{
+ I18nRegister(NULL, Name());
+}
+
+void cPlugin::SetName(const char *s)
+{
+ name = s;
+}
+
+const char *cPlugin::CommandLineHelp(void)
+{
+ return NULL;
+}
+
+bool cPlugin::ProcessArgs(int argc, char *argv[])
+{
+ return true;
+}
+
+void cPlugin::Start(void)
+{
+}
+
+const char *cPlugin::MainMenuEntry(void)
+{
+ return NULL;
+}
+
+cOsdMenu *cPlugin::MainMenuAction(void)
+{
+ return NULL;
+}
+
+cMenuSetupPage *cPlugin::SetupMenu(void)
+{
+ return NULL;
+}
+
+bool cPlugin::SetupParse(const char *Name, const char *Value)
+{
+ return false;
+}
+
+void cPlugin::SetupStore(const char *Name, const char *Value)
+{
+ Setup.Store(Name, Value, this->Name());
+}
+
+void cPlugin::SetupStore(const char *Name, int Value)
+{
+ Setup.Store(Name, Value, this->Name());
+}
+
+void cPlugin::RegisterI18n(const tI18nPhrase * const Phrases)
+{
+ I18nRegister(Phrases, Name());
+}
+
+// --- cDll ------------------------------------------------------------------
+
+cDll::cDll(const char *FileName, const char *Args)
+{
+ fileName = strdup(FileName);
+ args = Args ? strdup(Args) : NULL;
+ handle = NULL;
+ plugin = NULL;
+}
+
+cDll::~cDll()
+{
+ delete plugin;
+ if (handle)
+ dlclose(handle);
+ delete args;
+ delete fileName;
+}
+
+static char *SkipQuote(char *s)
+{
+ char c = *s;
+ strcpy(s, s + 1);
+ while (*s && *s != c) {
+ if (*s == '\\')
+ strcpy(s, s + 1);
+ if (*s)
+ s++;
+ }
+ if (*s) {
+ strcpy(s, s + 1);
+ return s;
+ }
+ esyslog(LOG_ERR, "ERROR: missing closing %c", c);
+ fprintf(stderr, "vdr: missing closing %c\n", c);
+ return NULL;
+}
+
+bool cDll::Load(bool Log)
+{
+ if (Log)
+ isyslog(LOG_INFO, "loading plugin: %s", fileName);
+ if (handle) {
+ esyslog(LOG_ERR, "attempt to load plugin '%s' twice!", fileName);
+ return false;
+ }
+ handle = dlopen(fileName, RTLD_NOW);
+ const char *error = dlerror();
+ if (!error) {
+ void *(*creator)(void);
+ (void *)creator = dlsym(handle, "VDRPluginCreator");
+ if (!(error = dlerror()))
+ plugin = (cPlugin *)creator();
+ }
+ if (!error) {
+ if (plugin && args) {
+ int argc = 0;
+ char *argv[MAXPLUGINARGS];
+ char *p = args;
+ char *q = NULL;
+ bool done = false;
+ while (!done) {
+ if (!q)
+ q = p;
+ switch (*p) {
+ case '\\': strcpy(p, p + 1);
+ if (*p)
+ p++;
+ else {
+ esyslog(LOG_ERR, "ERROR: missing character after \\");
+ fprintf(stderr, "vdr: missing character after \\\n");
+ return false;
+ }
+ break;
+ case '"':
+ case '\'': if ((p = SkipQuote(p)) == NULL)
+ return false;
+ break;
+ default: if (!*p || isspace(*p)) {
+ done = !*p;
+ *p = 0;
+ if (q) {
+ if (argc < MAXPLUGINARGS - 1)
+ argv[argc++] = q;
+ else {
+ esyslog(LOG_ERR, "ERROR: plugin argument list too long");
+ fprintf(stderr, "vdr: plugin argument list too long\n");
+ return false;
+ }
+ q = NULL;
+ }
+ }
+ if (!done)
+ p++;
+ }
+ }
+ argv[argc] = NULL;
+ if (argc)
+ plugin->SetName(argv[0]);
+ optind = 0; // to reset the getopt() data
+ return !argc || plugin->ProcessArgs(argc, argv);
+ }
+ }
+ else {
+ esyslog(LOG_ERR, "ERROR: %s", error);
+ fprintf(stderr, "vdr: %s\n", error);
+ }
+ return !error && plugin;
+}
+
+// --- cPluginManager --------------------------------------------------------
+
+cPluginManager *cPluginManager::pluginManager = NULL;
+
+cPluginManager::cPluginManager(const char *Directory)
+{
+ directory = NULL;
+ if (pluginManager) {
+ fprintf(stderr, "vdr: attempt to create more than one plugin manager - exiting!\n");
+ exit(2);
+ }
+ SetDirectory(Directory);
+ pluginManager = this;
+}
+
+cPluginManager::~cPluginManager()
+{
+ Shutdown();
+ delete directory;
+ if (pluginManager == this)
+ pluginManager = NULL;
+}
+
+void cPluginManager::SetDirectory(const char *Directory)
+{
+ delete directory;
+ directory = Directory ? strdup(Directory) : NULL;
+}
+
+void cPluginManager::AddPlugin(const char *Args)
+{
+ if (strcmp(Args, "*") == 0) {
+ DIR *d = opendir(directory);
+ if (d) {
+ struct dirent *e;
+ while ((e = readdir(d)) != NULL) {
+ if (strstr(e->d_name, LIBVDR_PREFIX) == e->d_name) {
+ char *p = strstr(e->d_name, SO_INDICATOR);
+ if (p) {
+ *p = 0;
+ p += strlen(SO_INDICATOR);
+ if (strcmp(p, VDRVERSION) == 0) {
+ char *name = e->d_name + strlen(LIBVDR_PREFIX);
+ if (strcmp(name, "*") != 0) { // let's not get into a loop!
+ AddPlugin(e->d_name + strlen(LIBVDR_PREFIX));
+ }
+ }
+ }
+ }
+ }
+ closedir(d);
+ }
+ return;
+ }
+ char *s = strdup(Args);
+ char *p = strchr(s, ' ');
+ if (p)
+ *p = 0;
+ char *buffer = NULL;
+ asprintf(&buffer, "%s/%s%s%s%s", directory, LIBVDR_PREFIX, s, SO_INDICATOR, VDRVERSION);
+ dlls.Add(new cDll(buffer, Args));
+ delete buffer;
+ delete s;
+}
+
+bool cPluginManager::LoadPlugins(bool Log)
+{
+ for (cDll *dll = dlls.First(); dll; dll = dlls.Next(dll)) {
+ if (!dll->Load(Log))
+ return false;
+ }
+ return true;
+}
+
+void cPluginManager::StartPlugins(void)
+{
+ for (cDll *dll = dlls.First(); dll; dll = dlls.Next(dll)) {
+ cPlugin *p = dll->Plugin();
+ if (p) {
+ int Language = Setup.OSDLanguage;
+ Setup.OSDLanguage = 0; // the i18n texts are only available _after_ Start()
+ isyslog(LOG_INFO, "starting plugin: %s (%s): %s", p->Name(), p->Version(), p->Description());
+ Setup.OSDLanguage = Language;
+ dll->Plugin()->Start();
+ }
+ }
+}
+
+bool cPluginManager::HasPlugins(void)
+{
+ return pluginManager && pluginManager->dlls.Count();
+}
+
+cPlugin *cPluginManager::GetPlugin(int Index)
+{
+ cDll *dll = pluginManager ? pluginManager->dlls.Get(Index) : NULL;
+ return dll ? dll->Plugin() : NULL;
+}
+
+cPlugin *cPluginManager::GetPlugin(const char *Name)
+{
+ if (pluginManager) {
+ for (cDll *dll = pluginManager->dlls.First(); dll; dll = pluginManager->dlls.Next(dll)) {
+ cPlugin *p = dll->Plugin();
+ if (p && strcmp(p->Name(), Name) == 0)
+ return p;
+ }
+ }
+ return NULL;
+}
+
+void cPluginManager::Shutdown(bool Log)
+{
+ cDll *dll;
+ while ((dll = dlls.Last()) != NULL) {
+ if (Log) {
+ cPlugin *p = dll->Plugin();
+ if (p)
+ isyslog(LOG_INFO, "stopping plugin: %s", p->Name());
+ }
+ dlls.Del(dll);
+ }
+}
diff --git a/plugin.h b/plugin.h
new file mode 100644
index 0000000..99f330d
--- /dev/null
+++ b/plugin.h
@@ -0,0 +1,81 @@
+/*
+ * plugin.h: The VDR plugin interface
+ *
+ * See the main source file 'vdr.c' for copyright information and
+ * how to reach the author.
+ *
+ * $Id: plugin.h 1.1 2002/05/09 10:16:09 kls Exp $
+ */
+
+#ifndef __PLUGIN_H
+#define __PLUGIN_H
+
+#include "i18n.h"
+#include "menuitems.h"
+#include "osd.h"
+#include "tools.h"
+
+#define VDRPLUGINCREATOR(PluginClass) extern "C" void *VDRPluginCreator(void) { return new PluginClass; }
+
+class cPlugin {
+ friend class cDll;
+private:
+ const char *name;
+ void SetName(const char *s);
+public:
+ cPlugin(void);
+ virtual ~cPlugin();
+
+ const char *Name(void) { return name; }
+ virtual const char *Version(void) = 0;
+ virtual const char *Description(void) = 0;
+ virtual const char *CommandLineHelp(void);
+
+ virtual bool ProcessArgs(int argc, char *argv[]);
+ virtual void Start(void);
+
+ virtual const char *MainMenuEntry(void);
+ virtual cOsdMenu *MainMenuAction(void);
+
+ virtual cMenuSetupPage *SetupMenu(void);
+ virtual bool SetupParse(const char *Name, const char *Value);
+ void SetupStore(const char *Name, const char *Value = NULL);
+ void SetupStore(const char *Name, int Value);
+
+ void RegisterI18n(const tI18nPhrase * const Phrases);
+ };
+
+class cDll : public cListObject {
+private:
+ char *fileName;
+ char *args;
+ void *handle;
+ cPlugin *plugin;
+public:
+ cDll(const char *FileName, const char *Args);
+ virtual ~cDll();
+ bool Load(bool Log = false);
+ cPlugin *Plugin(void) { return plugin; }
+ };
+
+class cDlls : public cList<cDll> {};
+
+class cPluginManager {
+private:
+ static cPluginManager *pluginManager;
+ char *directory;
+ cDlls dlls;
+public:
+ cPluginManager(const char *Directory);
+ virtual ~cPluginManager();
+ void SetDirectory(const char *Directory);
+ void AddPlugin(const char *Args);
+ bool LoadPlugins(bool Log = false);
+ void StartPlugins(void);
+ static bool HasPlugins(void);
+ static cPlugin *GetPlugin(int Index);
+ static cPlugin *GetPlugin(const char *Name);
+ void Shutdown(bool Log = false);
+ };
+
+#endif //__PLUGIN_H
diff --git a/recording.c b/recording.c
index b19e8b7..e637045 100644
--- a/recording.c
+++ b/recording.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: recording.c 1.60 2002/04/01 10:51:23 kls Exp $
+ * $Id: recording.c 1.61 2002/04/21 14:02:55 kls Exp $
*/
#include "recording.h"
@@ -222,7 +222,6 @@ static char *ExchangeChars(char *s, bool ToFileSystem)
case '+':
case ',':
case '-':
- case '.':
case ';':
case '=':
case '0' ... '9':
@@ -237,7 +236,8 @@ static char *ExchangeChars(char *s, bool ToFileSystem)
case ' ': *p = '_'; break;
case '~': *p = '/'; break;
// characters that have to be encoded:
- default: {
+ default:
+ if (*p != '.' || !*(p + 1) || *(p + 1) == '~') { // Windows can't handle '.' at the end of directory names
int l = p - s;
s = (char *)realloc(s, strlen(s) + 10);
p = s + l;
diff --git a/remote.h b/remote.h
index bbdf2fa..184a42e 100644
--- a/remote.h
+++ b/remote.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: remote.h 1.15 2001/07/22 14:42:59 kls Exp $
+ * $Id: remote.h 1.16 2002/05/09 11:43:04 kls Exp $
*/
#ifndef __REMOTE_H
@@ -95,7 +95,7 @@ public:
#elif !defined REMOTE_NONE
-#error Please define a remote control mode!
+// #error Please define a remote control mode!
#endif
diff --git a/ringbuffer.c b/ringbuffer.c
index 8b8420c..a52683d 100644
--- a/ringbuffer.c
+++ b/ringbuffer.c
@@ -7,7 +7,7 @@
* Parts of this file were inspired by the 'ringbuffy.c' from the
* LinuxDVB driver (see linuxtv.org).
*
- * $Id: ringbuffer.c 1.5 2001/11/03 09:50:46 kls Exp $
+ * $Id: ringbuffer.c 1.6 2002/04/18 15:46:36 kls Exp $
*/
#include "ringbuffer.h"
@@ -154,7 +154,6 @@ int cRingBufferLinear::Put(const uchar *Data, int Count)
Lock();
int rest = Size() - head;
int diff = tail - head;
- Unlock();
int free = (diff > 0) ? diff - 1 : Size() + diff - 1;
if (statistics) {
int fill = Size() - free - 1 + Count;
@@ -167,22 +166,25 @@ int cRingBufferLinear::Put(const uchar *Data, int Count)
dsyslog(LOG_INFO, "buffer usage: %d%%", percent);
}
}
- if (free <= 0)
- return 0;
- if (free < Count)
- Count = free;
- if (Count > maxFill)
- maxFill = Count;
- if (Count >= rest) {
- memcpy(buffer + head, Data, rest);
- if (Count - rest)
- memcpy(buffer, Data + rest, Count - rest);
- head = Count - rest;
- }
- else {
- memcpy(buffer + head, Data, Count);
- head += Count;
+ if (free > 0) {
+ if (free < Count)
+ Count = free;
+ if (Count > maxFill)
+ maxFill = Count;
+ if (Count >= rest) {
+ memcpy(buffer + head, Data, rest);
+ if (Count - rest)
+ memcpy(buffer, Data + rest, Count - rest);
+ head = Count - rest;
+ }
+ else {
+ memcpy(buffer + head, Data, Count);
+ head += Count;
+ }
}
+ else
+ Count = 0;
+ Unlock();
}
return Count;
}
@@ -193,22 +195,24 @@ int cRingBufferLinear::Get(uchar *Data, int Count)
Lock();
int rest = Size() - tail;
int diff = head - tail;
- Unlock();
int cont = (diff >= 0) ? diff : Size() + diff;
- if (rest <= 0)
- return 0;
- if (cont < Count)
- Count = cont;
- if (Count >= rest) {
- memcpy(Data, buffer + tail, rest);
- if (Count - rest)
- memcpy(Data + rest, buffer, Count - rest);
- tail = Count - rest;
- }
- else {
- memcpy(Data, buffer + tail, Count);
- tail += Count;
+ if (rest > 0) {
+ if (cont < Count)
+ Count = cont;
+ if (Count >= rest) {
+ memcpy(Data, buffer + tail, rest);
+ if (Count - rest)
+ memcpy(Data + rest, buffer, Count - rest);
+ tail = Count - rest;
+ }
+ else {
+ memcpy(Data, buffer + tail, Count);
+ tail += Count;
+ }
}
+ else
+ Count = 0;
+ Unlock();
}
return Count;
}
diff --git a/tools.c b/tools.c
index 099fb7d..6f99ef0 100644
--- a/tools.c
+++ b/tools.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: tools.c 1.62 2002/03/31 20:51:06 kls Exp $
+ * $Id: tools.c 1.63 2002/05/01 16:20:30 kls Exp $
*/
#include "tools.h"
@@ -251,10 +251,10 @@ int FreeDiskSpaceMB(const char *Directory, int *UsedMB)
int Free = 0;
struct statfs statFs;
if (statfs(Directory, &statFs) == 0) {
- int blocksPerMeg = 1024 * 1024 / statFs.f_bsize;
+ double blocksPerMeg = 1024.0 * 1024.0 / statFs.f_bsize;
if (UsedMB)
- *UsedMB = (statFs.f_blocks - statFs.f_bfree) / blocksPerMeg;
- Free = statFs.f_bavail / blocksPerMeg;
+ *UsedMB = int((statFs.f_blocks - statFs.f_bfree) / blocksPerMeg);
+ Free = int(statFs.f_bavail / blocksPerMeg);
}
else
LOG_ERROR_STR(Directory);
diff --git a/vdr.1 b/vdr.1
index b26a9df..06c0b84 100644
--- a/vdr.1
+++ b/vdr.1
@@ -8,9 +8,9 @@
.\" License as specified in the file COPYING that comes with the
.\" vdr distribution.
.\"
-.\" $Id: vdr.1 1.3 2002/04/07 13:11:43 kls Exp $
+.\" $Id: vdr.1 1.4 2002/05/09 16:04:17 kls Exp $
.\"
-.TH vdr 1 "7 Apr 2002" "1.0.0" "Video Disk Recorder"
+.TH vdr 1 "9 May 2002" "1.1.0" "Video Disk Recorder"
.SH NAME
vdr - the Video Disk Recorder
.SH SYNOPSIS
@@ -68,6 +68,11 @@ Set logging to \fIlevel\fR.
\fB2\fR\ =\ errors and info, \fB3\fR\ =\ errors, info and debug.
The default logging level is \fB3\fR.
.TP
+.BI -L\ dir ,\ --lib= dir
+Search for plugins in directory \fIdir\fR (default is ./PLUGINS/lib).
+There can be several \fB-L\fR options with different \fIdir\fR values.
+Each of them will apply to the \fB-P\fR options following it.
+.TP
.B -m, --mute
Mute audio of the primary DVB device at startup.
.TP
@@ -77,6 +82,18 @@ The default SVDRP port is \fB2001\fR.
You need to edit the file \fIsvdrphosts.conf\fR in order to enable
access to the SVDRP port.
.TP
+.BI -P\ options ,\ --plugin= options
+Load a plugin, defined by the given \fIoptions\fR.
+The first word in \fIoptions\fR must be the name of an existing \fBvdr\fR
+plugin, optionally followed by a blank separated list of command line options
+for that plugin. If \fIoptions\fR contains any blanks, you need to enclose it
+in quotes, like for example
+
+\fBvdr -P "abc -a -b xyz"\fR
+
+which would load a plugin named \fBabc\fR, giving it the command line options
+\fB-a\ -b\ xyz\fR.
+.TP
.BI -r\ cmd ,\ --record= cmd
Call \fIcmd\fR before and after a recording.
.TP
@@ -104,6 +121,9 @@ Successful program execution.
.B 1
An error has been detected which requires the DVB driver and \fBvdr\fR
to be re-loaded.
+.TP
+.B 2
+An non-recoverable error has been detected, \fBvdr\fR has given up.
.SH FILES
.TP
.I channels.conf
diff --git a/vdr.c b/vdr.c
index 874e826..7bb1f9b 100644
--- a/vdr.c
+++ b/vdr.c
@@ -22,7 +22,7 @@
*
* The project's page is at http://www.cadsoft.de/people/kls/vdr
*
- * $Id: vdr.c 1.102 2002/03/29 10:09:20 kls Exp $
+ * $Id: vdr.c 1.104 2002/05/05 10:34:31 kls Exp $
*/
#include <getopt.h>
@@ -36,6 +36,7 @@
#include "i18n.h"
#include "interface.h"
#include "menu.h"
+#include "plugin.h"
#include "recording.h"
#include "tools.h"
#include "videodir.h"
@@ -79,14 +80,18 @@ int main(int argc, char *argv[])
#define DEFAULTSVDRPPORT 2001
#define DEFAULTWATCHDOG 0 // seconds
+#define DEFAULTPLUGINDIR "./PLUGINS/lib"
int SVDRPport = DEFAULTSVDRPPORT;
const char *ConfigDirectory = NULL;
+ bool DisplayHelp = false;
+ bool DisplayVersion = false;
bool DaemonMode = false;
bool MuteAudio = false;
int WatchdogTimeout = DEFAULTWATCHDOG;
const char *Terminal = NULL;
const char *Shutdown = NULL;
+ cPluginManager PluginManager(DEFAULTPLUGINDIR);
static struct option long_options[] = {
{ "audio", required_argument, NULL, 'a' },
@@ -95,8 +100,10 @@ int main(int argc, char *argv[])
{ "device", required_argument, NULL, 'D' },
{ "epgfile", required_argument, NULL, 'E' },
{ "help", no_argument, NULL, 'h' },
+ { "lib", required_argument, NULL, 'L' },
{ "log", required_argument, NULL, 'l' },
{ "mute", no_argument, NULL, 'm' },
+ { "plugin", required_argument, NULL, 'P' },
{ "port", required_argument, NULL, 'p' },
{ "record", required_argument, NULL, 'r' },
{ "shutdown", required_argument, NULL, 's' },
@@ -108,8 +115,7 @@ int main(int argc, char *argv[])
};
int c;
- int option_index = 0;
- while ((c = getopt_long(argc, argv, "a:c:dD:E:hl:mp:r:s:t:v:Vw:", long_options, &option_index)) != -1) {
+ while ((c = getopt_long(argc, argv, "a:c:dD:E:hl:L:mp:P:r:s:t:v:Vw:", long_options, NULL)) != -1) {
switch (c) {
case 'a': cDvbApi::SetAudioCommand(optarg);
break;
@@ -128,40 +134,7 @@ int main(int argc, char *argv[])
break;
case 'E': cSIProcessor::SetEpgDataFileName(*optarg != '-' ? optarg : NULL);
break;
- case 'h': printf("Usage: vdr [OPTION]\n\n" // for easier orientation, this is column 80|
- " -a CMD, --audio=CMD send Dolby Digital audio to stdin of command CMD\n"
- " -c DIR, --config=DIR read config files from DIR (default is to read them\n"
- " from the video directory)\n"
- " -d, --daemon run in daemon mode\n"
- " -D NUM, --device=NUM use only the given DVB device (NUM = 0, 1, 2...)\n"
- " there may be several -D options (default: all DVB\n"
- " devices will be used)\n"
- " -E FILE --epgfile=FILE write the EPG data into the given FILE (default is\n"
- " %s); use '-E-' to disable this\n"
- " if FILE is a directory, the default EPG file will be\n"
- " created in that directory\n"
- " -h, --help print this help and exit\n"
- " -l LEVEL, --log=LEVEL set log level (default: 3)\n"
- " 0 = no logging, 1 = errors only,\n"
- " 2 = errors and info, 3 = errors, info and debug\n"
- " -m, --mute mute audio of the primary DVB device at startup\n"
- " -p PORT, --port=PORT use PORT for SVDRP (default: %d)\n"
- " 0 turns off SVDRP\n"
- " -r CMD, --record=CMD call CMD before and after a recording\n"
- " -s CMD, --shutdown=CMD call CMD to shutdown the computer\n"
- " -t TTY, --terminal=TTY controlling tty\n"
- " -V, --version print version information and exit\n"
- " -v DIR, --video=DIR use DIR as video directory (default: %s)\n"
- " -w SEC, --watchdog=SEC activate the watchdog timer with a timeout of SEC\n"
- " seconds (default: %d); '0' disables the watchdog\n"
- "\n"
- "Report bugs to <vdr-bugs@cadsoft.de>\n",
- cSIProcessor::GetEpgDataFileName() ? cSIProcessor::GetEpgDataFileName() : "'-'",
- DEFAULTSVDRPPORT,
- VideoDirectory,
- DEFAULTWATCHDOG
- );
- return 0;
+ case 'h': DisplayHelp = true;
break;
case 'l': if (isnumber(optarg)) {
int l = atoi(optarg);
@@ -173,6 +146,8 @@ int main(int argc, char *argv[])
fprintf(stderr, "vdr: invalid log level: %s\n", optarg);
return 2;
break;
+ case 'L': PluginManager.SetDirectory(optarg);
+ break;
case 'm': MuteAudio = true;
break;
case 'p': if (isnumber(optarg))
@@ -182,14 +157,15 @@ int main(int argc, char *argv[])
return 2;
}
break;
+ case 'P': PluginManager.AddPlugin(optarg);
+ break;
case 'r': cRecordingUserCommand::SetCommand(optarg);
break;
case 's': Shutdown = optarg;
break;
case 't': Terminal = optarg;
break;
- case 'V': printf("vdr, version %s\n", VDRVERSION);
- return 0;
+ case 'V': DisplayVersion = true;
break;
case 'v': VideoDirectory = optarg;
while (optarg && *optarg && optarg[strlen(optarg) - 1] == '/')
@@ -209,6 +185,71 @@ int main(int argc, char *argv[])
}
}
+ // Help and version info:
+
+ if (DisplayHelp || DisplayVersion) {
+ if (!PluginManager.HasPlugins())
+ PluginManager.AddPlugin("*"); // adds all available plugins
+ PluginManager.LoadPlugins();
+ if (DisplayHelp) {
+ printf("Usage: vdr [OPTIONS]\n\n" // for easier orientation, this is column 80|
+ " -a CMD, --audio=CMD send Dolby Digital audio to stdin of command CMD\n"
+ " -c DIR, --config=DIR read config files from DIR (default is to read them\n"
+ " from the video directory)\n"
+ " -d, --daemon run in daemon mode\n"
+ " -D NUM, --device=NUM use only the given DVB device (NUM = 0, 1, 2...)\n"
+ " there may be several -D options (default: all DVB\n"
+ " devices will be used)\n"
+ " -E FILE --epgfile=FILE write the EPG data into the given FILE (default is\n"
+ " %s); use '-E-' to disable this\n"
+ " if FILE is a directory, the default EPG file will be\n"
+ " created in that directory\n"
+ " -h, --help print this help and exit\n"
+ " -l LEVEL, --log=LEVEL set log level (default: 3)\n"
+ " 0 = no logging, 1 = errors only,\n"
+ " 2 = errors and info, 3 = errors, info and debug\n"
+ " -L DIR, --lib=DIR search for plugins in DIR (default is %s)\n"
+ " -m, --mute mute audio of the primary DVB device at startup\n"
+ " -p PORT, --port=PORT use PORT for SVDRP (default: %d)\n"
+ " 0 turns off SVDRP\n"
+ " -P OPT, --plugin=OPT load a plugin defined by the given options\n"
+ " -r CMD, --record=CMD call CMD before and after a recording\n"
+ " -s CMD, --shutdown=CMD call CMD to shutdown the computer\n"
+ " -t TTY, --terminal=TTY controlling tty\n"
+ " -v DIR, --video=DIR use DIR as video directory (default: %s)\n"
+ " -V, --version print version information and exit\n"
+ " -w SEC, --watchdog=SEC activate the watchdog timer with a timeout of SEC\n"
+ " seconds (default: %d); '0' disables the watchdog\n"
+ "\n",
+ cSIProcessor::GetEpgDataFileName() ? cSIProcessor::GetEpgDataFileName() : "'-'",
+ DEFAULTPLUGINDIR,
+ DEFAULTSVDRPPORT,
+ VideoDirectory,
+ DEFAULTWATCHDOG
+ );
+ }
+ if (DisplayVersion)
+ printf("vdr (%s) - The Video Disk Recorder\n", VDRVERSION);
+ if (PluginManager.HasPlugins()) {
+ if (DisplayHelp)
+ printf("Plugins: vdr -P\"name [OPTIONS]\"\n\n");
+ for (int i = 0; ; i++) {
+ cPlugin *p = PluginManager.GetPlugin(i);
+ if (p) {
+ const char *help = p->CommandLineHelp();
+ printf("%s (%s) - %s\n", p->Name(), p->Version(), p->Description());
+ if (DisplayHelp && help) {
+ printf("\n");
+ puts(help);
+ }
+ }
+ else
+ break;
+ }
+ }
+ return 0;
+ }
+
// Log file:
if (SysLogLevel > 0)
@@ -250,6 +291,11 @@ int main(int argc, char *argv[])
isyslog(LOG_INFO, "VDR version %s started", VDRVERSION);
+ // Load plugins:
+
+ if (!PluginManager.LoadPlugins(true))
+ return 2;
+
// Configuration data:
if (!ConfigDirectory)
@@ -276,6 +322,12 @@ int main(int argc, char *argv[])
cSIProcessor::Read();
+ // Start plugins:
+
+ PluginManager.StartPlugins();
+
+ // Channel:
+
Channels.SwitchTo(Setup.CurrentChannel);
if (MuteAudio)
cDvbApi::PrimaryDvbApi->ToggleMute();
@@ -469,7 +521,7 @@ int main(int argc, char *argv[])
Interface->Info(tr("Editing process finished"));
}
}
- if (!*Interact && (!cRecordControls::Active() || ForceShutdown)) {
+ if (!*Interact && ((!cRecordControls::Active() && !cVideoCutter::Active()) || ForceShutdown)) {
time_t Now = time(NULL);
if (Now - LastActivity > ACTIVITYTIMEOUT) {
// Shutdown:
@@ -529,6 +581,7 @@ int main(int argc, char *argv[])
Setup.CurrentChannel = cDvbApi::CurrentChannel();
Setup.CurrentVolume = cDvbApi::CurrentVolume();
Setup.Save();
+ PluginManager.Shutdown(true);
cVideoCutter::Stop();
delete Menu;
delete ReplayControl;