summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKlaus Schmidinger <kls (at) cadsoft (dot) de>2001-09-02 18:00:00 +0200
committerKlaus Schmidinger <kls (at) cadsoft (dot) de>2001-09-02 18:00:00 +0200
commitbb18b9e0b449afff418f010c1b2e255acd3fbad3 (patch)
tree0c7d94f019a386ae0cc1ca8a3b6e669e68353dff
parentae8fe25312b6b0ec18fd0c6c2a275f334ada02db (diff)
downloadvdr-patch-lnbsharing-bb18b9e0b449afff418f010c1b2e255acd3fbad3.tar.gz
vdr-patch-lnbsharing-bb18b9e0b449afff418f010c1b2e255acd3fbad3.tar.bz2
Version 0.94vdr-0.94
- Implemented automatic shutdown (see INSTALL and MANUAL for details). - New SVDRP command NEXT to show the next timer event. - The new remote control key "Power" can be used to turn the VDR machine off (this requires the presence of the '-s' option). - Fixed code for the default "Ok" button on the PC keyboard (was 0x162 on the "good old" keyboards (with the F-keys at the left side), while it changed to 0x15E on the newer keyboards). - When a recording is edited, the summary information (if present) is now also copied. - When a recording is running on the primary interface, any attempt to change the current channel will now lead to a "Channel locked" message. - The main program loop now first checks whether any timer recordings are finished, before starting a new timer recording. This is important in case one timer ends at the same time another timer starts. - New setup parameter OSDMessageTime to define how long an OSD message shall be displayed. - The "File" parameter of a timer can now contain the '~' character to store the recording in a hierarchical directory structure. The '~' character has been chosen since the file system's directory delimiter '/' may be part of a regular programme name (showing the directory hierarchy in the "Recordings" menu will follow later). - Repeating timers now create recordings that contain the 'Subtitle' information from the EPG data in their file name. Typically (on tv stations that care about their viewers) this contains the episode title of a series. The subtitle is appended to the timer's file name, separated by a '~' character, so that it results in all recordings of this timer being collected in a common subdirectory. You can disable this with the 'UseSubtitle' parameter in the "Setup" menu. - The summary information is now taken from the EPG data at the actual time of recording (no longer at the time the timer is created in the "Schedule" menu). If a timer already has summary data, that data will be used. If you have repeating timers in your 'timers.conf', you may want to make sure they do NOT contain any summary information (that's the last field in the timer definitions). Use your favourite text editor to delete that information. That way every recording will store the actual summary data at the time of the recording.
-rw-r--r--FORMATS4
-rw-r--r--HISTORY39
-rw-r--r--INSTALL52
-rw-r--r--MANUAL34
-rw-r--r--Makefile29
-rw-r--r--config.c35
-rw-r--r--config.h10
-rw-r--r--dvbapi.c6
-rw-r--r--i18n.c74
-rw-r--r--interface.c15
-rw-r--r--interface.h8
-rw-r--r--keys-pc.confbin283 -> 300 bytes
-rw-r--r--libdtv/x.txt55
-rw-r--r--menu.c38
-rw-r--r--menu.h6
-rw-r--r--recording.c49
-rw-r--r--recording.h5
-rw-r--r--svdrp.c35
-rw-r--r--svdrp.h3
-rw-r--r--vdr.c124
-rw-r--r--videodir.c22
21 files changed, 456 insertions, 187 deletions
diff --git a/FORMATS b/FORMATS
index 03739ee..3c5d36d 100644
--- a/FORMATS
+++ b/FORMATS
@@ -67,7 +67,9 @@ Video Disk Recorder File Formats
be automatically deleted by a new recording with higher priority, 99 means
that this recording will never be automatically deleted
- Name of timer (will be used to name the recording); if the name contains
- any ':' characters, these have to be replaced with '|'
+ any ':' characters, these have to be replaced with '|'. If the name shall
+ contain subdirectories, these have to be delimited by '~' (since the '/'
+ character may be part of a regular programme name).
- Summary (any newline characters in the summary have to be replaced with '|';
the summary may contain ':' characters)
diff --git a/HISTORY b/HISTORY
index 250d857..d2be054 100644
--- a/HISTORY
+++ b/HISTORY
@@ -676,3 +676,42 @@ Video Disk Recorder Revision History
- Timers are now sorted in the "Timers" menu, showing the sequence in which
they will be recording. This can be disabled in the "Setup" menu. Note
that the "Mark" button doesn't work if timers are displayed sorted.
+
+2001-09-02: Version 0.94
+
+- Implemented automatic shutdown (see INSTALL and MANUAL for details).
+- New SVDRP command NEXT to show the next timer event.
+- The new remote control key "Power" can be used to turn the VDR machine
+ off (this requires the presence of the '-s' option).
+- Fixed code for the default "Ok" button on the PC keyboard (was 0x162 on
+ the "good old" keyboards (with the F-keys at the left side), while it changed
+ to 0x15E on the newer keyboards).
+- When a recording is edited, the summary information (if present) is now
+ also copied.
+- When a recording is running on the primary interface, any attempt to change
+ the current channel will now lead to a "Channel locked" message.
+- The main program loop now first checks whether any timer recordings are
+ finished, before starting a new timer recording. This is important in case
+ one timer ends at the same time another timer starts.
+- New setup parameter OSDMessageTime to define how long an OSD message shall
+ be displayed.
+- The "File" parameter of a timer can now contain the '~' character to store
+ the recording in a hierarchical directory structure. The '~' character has
+ been chosen since the file system's directory delimiter '/' may be part of
+ a regular programme name (showing the directory hierarchy in the "Recordings"
+ menu will follow later).
+- Repeating timers now create recordings that contain the 'Subtitle' information
+ from the EPG data in their file name. Typically (on tv stations that care
+ about their viewers) this contains the episode title of a series. The
+ subtitle is appended to the timer's file name, separated by a '~' character,
+ so that it results in all recordings of this timer being collected in a
+ common subdirectory. You can disable this with the 'UseSubtitle' parameter
+ in the "Setup" menu.
+- The summary information is now taken from the EPG data at the actual time of
+ recording (no longer at the time the timer is created in the "Schedule" menu).
+ If a timer already has summary data, that data will be used. If you have
+ repeating timers in your 'timers.conf', you may want to make sure they do
+ NOT contain any summary information (that's the last field in the timer
+ definitions). Use your favourite text editor to delete that information.
+ That way every recording will store the actual summary data at the time of
+ the recording.
diff --git a/INSTALL b/INSTALL
index 946e06d..e15f13e 100644
--- a/INSTALL
+++ b/INSTALL
@@ -98,6 +98,57 @@ call to the VDR program, be sure to NOT use the '-d' option! Otherwise
VDR will go into 'deamon' mode and the initial program call will return
immediately!
+Automatic shutdown:
+-------------------
+
+If you define a shutdown command via the '-s' command line option, VDR
+will call the given command if there is currently no recording or replay
+active, the user has been inactive for at least MinUserInactivity minutes
+and the next timer event is at least MinEventTimeout minutes in the future
+(see the Setup parameters in MANUAL).
+
+The command given in the '-s' option will be called with two parameters.
+The first one is the time (in UTC) of the next timer event (as a time_t
+type number), and the second one is the number of seconds from the current
+time until the next timer event. Your program can choose which one to use
+for programming some sort of hardware device that makes sure the computer
+will be restarted in time before the next timer event. Your program must
+also initiate the actual shutdown procedure of the computer. After this
+your program should return to VDR. VDR will not automatically exit after
+calling the shutdown program, but will rather continue normally untit it
+receives a SIGTERM when the computer is actually shut down. So in case
+the shutdown fails, or the shutdown program for some reason decides not to
+perform a shutdown, VDR will stay up and running.
+
+If there are currently no timers active, both parameters will be '0'.
+In that case the program shall not set the hardware for automatic restart
+and only perform the system shutdown. A program that uses the second parameter
+to set the hardware for restart must therefore also check whether the first
+parameter is '0'.
+
+Before the shutdown program is called, the user will be prompted to inform
+him that the system is about to shut down. If any remote control key is
+pressed while this prompt is visible, the shutdown will be cancelled (and
+tried again after another MinUserInactivity minutes). The shutdown prompt
+will be displayed for 5 minutes, which should be enough time for the user
+to react.
+
+A sample shell script to be used with the '-s' option might look like this:
+
+#!/bin/sh
+setRTCwakeup $(($1 - 300))
+sudo halt
+
+Here 'setRTCwakeup' would be some program that uses the first parameter
+(which is the absolute time of the next timer event) to set the Real Time
+Clock so that it wakes up the computer 5 minutes (i.e. 300 seconds) before
+that event. The 'sudo halt' command then shuts down the computer.
+You will have to substitute both commands with whatever applies to your
+particular hard- and software environment.
+
+If the '-s' option is present, the VDR machine can be turned off by pressing
+the "Power" key on the remote control.
+
Command line options:
---------------------
@@ -239,6 +290,7 @@ The default PC key assignments are:
Back 'End' in numeric block
Red, Green, Yellow, Blue 'F1'..'F4'
0..9 '0'..'9' in top row
+ Power 'P'
If you prefer different key assignments, or if the default doesn't work for
your keyboard, simply delete the file 'keys-pc.conf' and restart 'vdr' to get
diff --git a/MANUAL b/MANUAL
index ae93099..c6b5efd 100644
--- a/MANUAL
+++ b/MANUAL
@@ -22,6 +22,7 @@ Video Disk Recorder User's Manual
Yellow - Eject DVD Delete Delete - Delete Skip +60s
Blue - Resume Mark Mark(1) - Summary Stop
0..9 Ch select - - - Numeric inp. - Editing
+ Power Shutdown - - - - - -
(1) The "Mark" button in the "Timers" menu only works if sorting the timers
has been disabled in the "Setup" menu.
@@ -284,6 +285,18 @@ Video Disk Recorder User's Manual
time, so it is possible to have a "repeating timer" store all its
recordings under the same name; they will be distinguishable by
their date and time).
+ If the file name contains the special character '~', the recording
+ will be stored in a hierarchical directory structure. For instance,
+ a file name of "Sci-Fi~Star Trek~Voyager" will result in a directory
+ structure "/video/Sci-Fi/Star_Trek/Voyager". The '~' character has
+ been chosen for this since the file system's directory delimiter '/'
+ may be part of a regular programme name.
+ Repeating timers create recordings that contain the 'Subtitle'
+ information from the EPG data in their file name. Typically (on tv
+ stations that care about their viewers) this contains the episode
+ title of a series. The subtitle is appended to the timer's file name,
+ separated by a '~' character, so that it results in all recordings
+ of this timer being collected in a common subdirectory.
If this field is left blank, the channel name will be used to form
the name of the recording.
@@ -401,6 +414,14 @@ Video Disk Recorder User's Manual
means that this recording will never be deleted
automatically.
+ UseSubtitle = 1 Repeating timers use the EPG's 'Subtitle' information to
+ create recording file names in a hierarchical structure
+ (for instance to gather all episodes of a series in a
+ common subdirectory). This parameter can be used to
+ control this.
+ 0 = don't use the 'Subtitle'
+ 1 = use it (and create subdirectories)
+
VideoFormat = 0 The video format (or aspect ratio) of the tv set in use.
0 = 4:3
1 = 16:9
@@ -412,11 +433,24 @@ Video Disk Recorder User's Manual
OSDwidth = 52 The width and height of the OSD .
OSDheight = 18 The valid ranges are width=40...56, height=12...21.
+ OSDMessageTime = 1 The time (in seconds) how long an informational
+ message shall be displayed on the OSD. The valid range
+ is 1...60.
+
MaxVideoFileSize=2000 The maximum size of a single recorded video file in MB.
The valid range is 100...2000. Default is 2000, but
you may want to use smaller values if you are planning
on archiving a recording to CD.
+ MinEventTimeout=120 If the command line option '-s' has been set, VDR will
+ MinUserInactivity=120 automatically shutdown the computer if the next timer
+ event is at least MinEventTimeout minutes in the future,
+ and the user has been inactive for at least
+ MinUserInactivity minutes. Setting MinUserInactivity
+ to 0 disables the automatic shutdown, while still
+ retaining the possibility to manually shutdown the
+ computer.
+
* Executing system commands
The "Main" menu option "Commands" allows you to execute any system commands
diff --git a/Makefile b/Makefile
index 067f34a..f39be08 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.26 2001/08/15 13:56:11 kls Exp $
+# $Id: Makefile 1.27 2001/08/31 13:13:30 kls Exp $
.DELETE_ON_ERROR:
@@ -59,25 +59,12 @@ font: genfontfile fontfix.c fontosd.c
# Dependencies:
-config.o : config.c config.h dvbapi.h dvbosd.h dvd.h eit.h font.h i18n.h interface.h remote.h svdrp.h thread.h tools.h
-dvbapi.o : dvbapi.c $(AC3DIR)/ac3.h config.h dvbapi.h dvbosd.h dvd.h eit.h font.h recording.h remux.h ringbuffer.h thread.h tools.h videodir.h
-dvbosd.o : dvbosd.c dvbosd.h font.h tools.h
-dvd.o : dvd.c dvd.h
-eit.o : eit.c config.h dvbapi.h dvbosd.h dvd.h eit.h font.h $(DTVDIR)/libdtv.h thread.h tools.h videodir.h
-font.o : font.c font.h fontfix.c fontosd.c tools.h
-i18n.o : i18n.c config.h dvbapi.h dvbosd.h dvd.h eit.h font.h i18n.h thread.h tools.h
-interface.o : interface.c config.h dvbapi.h dvbosd.h dvd.h eit.h font.h i18n.h interface.h remote.h svdrp.h thread.h tools.h
-menu.o : menu.c config.h dvbapi.h dvbosd.h dvd.h eit.h font.h i18n.h interface.h menu.h osd.h recording.h remote.h svdrp.h thread.h tools.h
-osd.o : osd.c config.h dvbapi.h dvbosd.h dvd.h eit.h font.h i18n.h interface.h osd.h remote.h svdrp.h thread.h tools.h
-recording.o : recording.c config.h dvbapi.h dvbosd.h dvd.h eit.h font.h interface.h recording.h remote.h svdrp.h thread.h tools.h videodir.h
-remote.o : remote.c config.h dvbapi.h dvbosd.h dvd.h eit.h font.h remote.h thread.h tools.h
-remux.o : remux.c remux.h thread.h tools.h
-ringbuffer.o: ringbuffer.c ringbuffer.h thread.h tools.h
-svdrp.o : svdrp.c config.h dvbapi.h dvbosd.h dvd.h eit.h font.h interface.h remote.h svdrp.h thread.h tools.h
-thread.o : thread.c thread.h tools.h
-tools.o : tools.c tools.h
-vdr.o : vdr.c config.h dvbapi.h dvbosd.h dvd.h eit.h font.h i18n.h interface.h menu.h osd.h recording.h remote.h svdrp.h thread.h tools.h videodir.h
-videodir.o : videodir.c tools.h videodir.h
+MAKEDEP = g++ -MM -MG
+DEPFILE = .dependencies
+$(DEPFILE): Makefile
+ @$(MAKEDEP) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@
+
+include $(DEPFILE)
# The main program:
@@ -111,7 +98,7 @@ $(DTVLIB) $(DTVDIR)/libdtv.h:
clean:
make -C $(AC3DIR) clean
make -C $(DTVDIR) clean
- -rm -f $(OBJS) vdr genfontfile genfontfile.o core *~
+ -rm -f $(OBJS) $(DEPFILE) vdr genfontfile genfontfile.o core *~
fontclean:
-rm -f fontfix.c fontosd.c
CLEAN: clean fontclean
diff --git a/config.c b/config.c
index ad4b9da..a97d7e4 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.59 2001/08/26 14:46:43 kls Exp $
+ * $Id: config.c 1.64 2001/09/02 15:04:13 kls Exp $
*/
#include "config.h"
@@ -38,6 +38,7 @@ tKey keyTable[] = { // "Up" and "Down" must be the first two keys!
{ k7, "7", 0 },
{ k8, "8", 0 },
{ k9, "9", 0 },
+ { kPower, "Power", 0 },
{ kNone, "", 0 },
};
@@ -364,21 +365,6 @@ cTimer::cTimer(const cEventInfo *EventInfo)
if (!isempty(Title))
strn0cpy(file, EventInfo->GetTitle(), sizeof(file));
summary = NULL;
- const char *Subtitle = EventInfo->GetSubtitle();
- if (isempty(Subtitle))
- Subtitle = "";
- const char *Summary = EventInfo->GetExtendedDescription();
- if (isempty(Summary))
- Summary = "";
- if (*Subtitle || *Summary) {
- asprintf(&summary, "%s%s%s", Subtitle, (*Subtitle && *Summary) ? "\n\n" : "", Summary);
- char *p = summary;
- while (*p) {
- if (*p == '\n')
- *p = '|';
- p++;
- }
- }
}
cTimer::~cTimer()
@@ -570,7 +556,7 @@ bool cTimer::Matches(time_t t)
}
}
}
- return active && startTime <= t && t <= stopTime;
+ return active && startTime <= t && t < stopTime; // must stop *before* stopTime to allow adjacent timers
}
time_t cTimer::StartTime(void)
@@ -761,9 +747,8 @@ cTimer *cTimers::GetTimer(cTimer *Timer)
return NULL;
}
-cTimer *cTimers::GetMatch(void)
+cTimer *cTimers::GetMatch(time_t t)
{
- time_t t = time(NULL); // all timers must be checked against the exact same time to correctly handle Priority!
cTimer *t0 = NULL;
cTimer *ti = First();
while (ti) {
@@ -815,11 +800,15 @@ cSetup::cSetup(void)
PrimaryLimit = 0;
DefaultPriority = 50;
DefaultLifetime = 50;
+ UseSubtitle = 1;
VideoFormat = VIDEO_FORMAT_4_3;
ChannelInfoPos = 0;
OSDwidth = 52;
OSDheight = 18;
+ OSDMessageTime = 1;
MaxVideoFileSize = MAXVIDEOFILESIZE;
+ MinEventTimeout = 120;
+ MinUserInactivity = 120;
CurrentChannel = -1;
}
@@ -848,11 +837,15 @@ bool cSetup::Parse(char *s)
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, "VideoFormat")) VideoFormat = 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, "MinEventTimeout")) MinEventTimeout = atoi(Value);
+ else if (!strcasecmp(Name, "MinUserInactivity")) MinUserInactivity = atoi(Value);
else if (!strcasecmp(Name, "CurrentChannel")) CurrentChannel = atoi(Value);
else
return false;
@@ -916,11 +909,15 @@ bool cSetup::Save(const char *FileName)
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, "VideoFormat = %d\n", VideoFormat);
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, "MinEventTimeout = %d\n", MinEventTimeout);
+ fprintf(f, "MinUserInactivity = %d\n", MinUserInactivity);
fprintf(f, "CurrentChannel = %d\n", CurrentChannel);
f.Close();
isyslog(LOG_INFO, "saved setup to %s", FileName);
diff --git a/config.h b/config.h
index 70f3574..c3fab9a 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.66 2001/08/26 14:46:53 kls Exp $
+ * $Id: config.h 1.72 2001/09/02 15:45:17 kls Exp $
*/
#ifndef __CONFIG_H
@@ -19,7 +19,7 @@
#include "eit.h"
#include "tools.h"
-#define VDRVERSION "0.93"
+#define VDRVERSION "0.94"
#define MaxBuffer 10000
@@ -44,6 +44,7 @@ enum eKeys { // "Up" and "Down" must be the first two keys!
kYellow,
kBlue,
k0, k1, k2, k3, k4, k5, k6, k7, k8, k9,
+ kPower,
kNone,
// The following flags are OR'd with the above codes:
k_Repeat = 0x8000,
@@ -255,7 +256,7 @@ public:
class cTimers : public cConfig<cTimer> {
public:
cTimer *GetTimer(cTimer *Timer);
- cTimer *GetMatch(void);
+ cTimer *GetMatch(time_t t);
cTimer *GetNextActiveTimer(void);
};
@@ -291,10 +292,13 @@ public:
int SortTimers;
int PrimaryLimit;
int DefaultPriority, DefaultLifetime;
+ int UseSubtitle;
int VideoFormat;
int ChannelInfoPos;
int OSDwidth, OSDheight;
+ int OSDMessageTime;
int MaxVideoFileSize;
+ int MinEventTimeout, MinUserInactivity;
int CurrentChannel;
cSetup(void);
bool Load(const char *FileName);
diff --git a/dvbapi.c b/dvbapi.c
index 51434e1..8e502ed 100644
--- a/dvbapi.c
+++ b/dvbapi.c
@@ -7,7 +7,7 @@
* DVD support initially written by Andreas Schultz <aschultz@warp10.net>
* based on dvdplayer-0.5 by Matjaz Thaler <matjaz.thaler@guest.arnes.si>
*
- * $Id: dvbapi.c 1.110 2001/08/25 13:52:38 kls Exp $
+ * $Id: dvbapi.c 1.111 2001/09/01 13:27:52 kls Exp $
*/
//#define DVDDEBUG 1
@@ -2256,8 +2256,10 @@ cCuttingBuffer *cVideoCutter::cuttingBuffer = NULL;
bool cVideoCutter::Start(const char *FileName)
{
if (!cuttingBuffer) {
- const char *EditedVersionName = PrefixVideoFileName(FileName, '%');
+ cRecording Recording(FileName);
+ const char *EditedVersionName = Recording.PrefixFileName('%');
if (EditedVersionName && RemoveVideoFile(EditedVersionName) && MakeDirs(EditedVersionName, true)) {
+ Recording.WriteSummary();
cuttingBuffer = new cCuttingBuffer(FileName, EditedVersionName);
return true;
}
diff --git a/i18n.c b/i18n.c
index 35a6bb1..086d85a 100644
--- a/i18n.c
+++ b/i18n.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: i18n.c 1.35 2001/08/26 13:45:10 kls Exp $
+ * $Id: i18n.c 1.39 2001/09/02 15:17:33 kls Exp $
*
* Slovenian translations provided by Miha Setina <mihasetina@softhome.net>
* Italian translations provided by Alberto Carraro <bertocar@tin.it>
@@ -385,6 +385,24 @@ const tPhrase Phrases[] = {
"Annuler les modifications?",
"Avbryte redigering",
},
+ { "Recording - shut down anyway?",
+ "Aufnahme läuft - trotzdem ausschalten?",
+ "", // TODO
+ "", // TODO
+ "", // TODO
+ "", // TODO
+ "", // TODO
+ "", // TODO
+ },
+ { "Press any key to cancel shutdown",
+ "Taste drücken um Shutdown abzubrechen",
+ "", // TODO
+ "", // TODO
+ "", // TODO
+ "", // TODO
+ "", // TODO
+ "", // TODO
+ },
// Channel parameters:
{ "Name",
"Name",
@@ -658,6 +676,15 @@ const tPhrase Phrases[] = {
"Montage déjà en cours!",
"Redigeringsprosessen er allerede aktiv!",
},
+ { "Can't shutdown - option '-s' not given!",
+ "Shutdown unmöglich - Option '-s' fehlt!",
+ "", // TODO
+ "", // TODO
+ "", // TODO
+ "", // TODO
+ "", // TODO
+ "", // TODO
+ },
// Setup parameters:
{ "OSD-Language",
"OSD-Sprache",
@@ -830,6 +857,15 @@ const tPhrase Phrases[] = {
"Durée de vie par défaut",
"Normal levetid (Timer)",
},
+ { "UseSubtitle",
+ "Subtitle verwenden",
+ "", // TODO
+ "", // TODO
+ "", // TODO
+ "", // TODO
+ "", // TODO
+ "", // TODO
+ },
{ "VideoFormat",
"Video Format",
"", // TODO
@@ -866,6 +902,15 @@ const tPhrase Phrases[] = {
"Hauteur affichage",
"", // TODO
},
+ { "OSDMessageTime",
+ "OSD Nachricht Dauer",
+ "", // TODO
+ "", // TODO
+ "", // TODO
+ "", // TODO
+ "", // TODO
+ "", // TODO
+ },
{ "MaxVideoFileSize",
"Max. Video Dateigröße",
"", // TODO
@@ -875,6 +920,24 @@ const tPhrase Phrases[] = {
"", // TODO
"", // TODO
},
+ { "MinEventTimeout",
+ "Mindest Event Pause",
+ "", // TODO
+ "", // TODO
+ "", // TODO
+ "", // TODO
+ "", // TODO
+ "", // TODO
+ },
+ { "MinUserInactivity",
+ "Mindest User Inaktivität",
+ "", // TODO
+ "", // TODO
+ "", // TODO
+ "", // TODO
+ "", // TODO
+ "", // TODO
+ },
// The days of the week:
{ "MTWTFSS",
"MDMDFSS",
@@ -1112,6 +1175,15 @@ const tPhrase Phrases[] = {
"Bleu",
"Blå",
},
+ { "Power",
+ "Ausschalten",
+ "", // TODO
+ "", // TODO
+ "", // TODO
+ "", // TODO
+ "", // TODO
+ "", // TODO
+ },
// Miscellaneous:
{ "yes",
"ja",
diff --git a/interface.c b/interface.c
index 1e06f4a..8695a36 100644
--- a/interface.c
+++ b/interface.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: interface.c 1.41 2001/08/25 13:15:00 kls Exp $
+ * $Id: interface.c 1.44 2001/09/01 15:18:46 kls Exp $
*/
#include "interface.h"
@@ -20,6 +20,7 @@ cInterface::cInterface(int SVDRPport)
cols[0] = 0;
width = height = 0;
keyFromWait = kNone;
+ interrupted = false;
rcIo = NULL;
SVDRP = NULL;
#if defined(REMOTE_RCU)
@@ -105,16 +106,19 @@ void cInterface::PutKey(eKeys Key)
eKeys cInterface::Wait(int Seconds, bool KeepChar)
{
+ if (Seconds == 0)
+ Seconds = Setup.OSDMessageTime;
Flush();
eKeys Key = kNone;
time_t timeout = time(NULL) + Seconds;
for (;;) {
Key = GetKey();
- if ((Key != kNone && (RAWKEY(Key) != kOk || RAWKEY(Key) == Key)) || time(NULL) > timeout)
+ if ((Key != kNone && (RAWKEY(Key) != kOk || RAWKEY(Key) == Key)) || time(NULL) > timeout || interrupted)
break;
}
if (KeepChar && ISRAWKEY(Key))
keyFromWait = Key;
+ interrupted = false;
return Key;
}
@@ -312,12 +316,13 @@ void cInterface::Error(const char *s)
Close();
}
-bool cInterface::Confirm(const char *s)
+bool cInterface::Confirm(const char *s, int Seconds, bool WaitForTimeout)
{
Open();
isyslog(LOG_INFO, "confirm: %s", s);
Status(s, clrBlack, clrYellow);
- bool result = Wait(10) == kOk;
+ eKeys k = Wait(Seconds);
+ bool result = WaitForTimeout ? k == kNone : k == kOk;
Status(NULL);
Close();
isyslog(LOG_INFO, "%sconfirmed", result ? "" : "not ");
@@ -353,7 +358,7 @@ void cInterface::QueryKeys(void)
WriteText(1, 5, tr("Press any key on the RC unit"));
Flush();
#ifndef REMOTE_KBD
- unsigned char Code = 0;
+ unsigned char Code = '0';
unsigned short Address;
#endif
for (;;) {
diff --git a/interface.h b/interface.h
index 2b0e2f1..dbfa1bc 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.22 2001/07/27 11:38:01 kls Exp $
+ * $Id: interface.h 1.24 2001/09/01 15:14:50 kls Exp $
*/
#ifndef __INTERFACE_H
@@ -23,17 +23,19 @@ private:
int open;
int cols[MaxCols];
eKeys keyFromWait;
+ bool interrupted;
cSVDRP *SVDRP;
cRcIoBase *rcIo;
unsigned int GetCh(bool Wait = true, bool *Repeat = NULL, bool *Release = NULL);
void QueryKeys(void);
void HelpButton(int Index, const char *Text, eDvbColor FgColor, eDvbColor BgColor);
- eKeys Wait(int Seconds = 1, bool KeepChar = false);
+ eKeys Wait(int Seconds = 0, bool KeepChar = false);
public:
cInterface(int SVDRPport = 0);
~cInterface();
void Open(int NumCols = 0, int NumLines = 0);
void Close(void);
+ void Interrupt(void) { interrupted = true; }
int Width(void) { return width; }
int Height(void) { return height; }
eKeys GetKey(bool Wait = true);
@@ -52,7 +54,7 @@ public:
void Status(const char *s, eDvbColor FgColor = clrBlack, eDvbColor BgColor = clrCyan);
void Info(const char *s);
void Error(const char *s);
- bool Confirm(const char *s);
+ bool Confirm(const char *s, int Seconds = 10, bool WaitForTimeout = false);
void Help(const char *Red, const char *Green = NULL, const char *Yellow = NULL, const char *Blue = NULL);
void LearnKeys(void);
void DisplayChannelNumber(int Number);
diff --git a/keys-pc.conf b/keys-pc.conf
index cb0192b..ab4b58d 100644
--- a/keys-pc.conf
+++ b/keys-pc.conf
Binary files differ
diff --git a/libdtv/x.txt b/libdtv/x.txt
deleted file mode 100644
index 0d12ddd..0000000
--- a/libdtv/x.txt
+++ /dev/null
@@ -1,55 +0,0 @@
-Hallo ZDF-EPG-Redaktion!
-
-Es würde mich interessieren, warum im digitalen EPG des
-ZDF (über Astra) die Beschreibung der Sendungen oftmals
-Trennungsstriche und zusätzliche Leerzeichen enthält.
-So zum Beispiel bei folgendem Eintrag:
-
-----------------------------------------------------
- ZDF 23.08 10:50 - 11:35
-
- Mit Leib und Seele
-
- Der einzige Mensch
-
- Stehlin hat die Frühmesse abge- sagt und sein
- Kommen im Pfarr- haus angekündigt. August, erbost
- über die Heimlichkeiten und Re- dereien von
- Stutz, erzwingt eine Aussprache mit Stehlin.
-----------------------------------------------------
-
-der ohne Trennungsstriche so aussehen könnte:
-
-----------------------------------------------------
- ZDF 23.08 10:50 - 11:35
-
- Mit Leib und Seele
-
- Der einzige Mensch
-
- Stehlin hat die Frühmesse abgesagt und sein
- Kommen im Pfarrhaus angekündigt. August, erbost
- über die Heimlichkeiten und Redereien von Stutz,
- erzwingt eine Aussprache mit Stehlin.
-----------------------------------------------------
-
-Ich kann mir das nur so erklären, daß Sie konkrete Annahmen
-darüber machen, mit welcher Zeilenlänge die Set-Top-Box diese
-Texte darstellt - aber das ist in meinen Augen eine ziemlich
-verwegene Annahme, denn es sollte ja wohl der STB überlassen bleiben,
-wie groß das Fenster für die Darstellung des EPG ist.
-
-Pro-7 zum Beispiel macht sowas nicht, wodurch der Text deultich
-besser dargestellt wird.
-
-Wenn Sie wenigstens nach dem (bzw. statt des) Bindestrich(s) ein deutlich
-erkennbares Sonderzeichen einfügen würden, dann könnte man das zuverlässig
-herausfiltern, aber so macht der ZDF-EPG immer wieder einen
-schlechten Eindruck.
-
-Über eine Antwort von Ihnen würde ich mich sehr freuen.
-
-MfG
-Klaus Schmidinger
-
-
diff --git a/menu.c b/menu.c
index 6d6eae8..5ff54cb 100644
--- a/menu.c
+++ b/menu.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: menu.c 1.109 2001/08/26 14:03:27 kls Exp $
+ * $Id: menu.c 1.115 2001/09/02 15:27:54 kls Exp $
*/
#include "menu.h"
@@ -19,7 +19,7 @@
#define MENUTIMEOUT 120 // seconds
#define MAXWAIT4EPGINFO 10 // seconds
-const char *FileNameChars = " aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789-.#^";
+const char *FileNameChars = " aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789-.#~^";
// --- cMenuEditItem ---------------------------------------------------------
@@ -494,6 +494,7 @@ eOSState cMenuEditStrItem::ProcessKey(eKeys Key)
if (value[pos] == '^')
value[pos] = 0;
pos = -1;
+ stripspace(value);
break;
}
// run into default
@@ -1159,17 +1160,6 @@ cMenuEvent::cMenuEvent(const cEventInfo *EventInfo, bool CanSwitch)
const char *Title = eventInfo->GetTitle();
const char *Subtitle = eventInfo->GetSubtitle();
const char *ExtendedDescription = eventInfo->GetExtendedDescription();
- // Some channels send a 'Subtitle' that should actually be the 'ExtendedDescription'
- // (their 'ExtendedDescription' is then empty). In order to handle this correctly
- // we silently shift that text to where it belongs.
- // The German TV station 'VOX' is notorious for this - why can't they do it correctly
- // like all the others? Well, at least like those who actually send the full range
- // of information (like, e.g., 'Sat.1'). Some stations (like 'RTL') don't even
- // bother sending anything but the 'Title'...
- if (isempty(ExtendedDescription) && !isempty(Subtitle) && int(strlen(Subtitle)) > 2 * Setup.OSDwidth) {
- ExtendedDescription = Subtitle;
- Subtitle = NULL;
- }
if (!isempty(Title)) {
Add(item = new cMenuTextItem(Title, 1, Line, Setup.OSDwidth - 2, -1, clrCyan));
Line += item->Height() + 1;
@@ -1726,11 +1716,15 @@ void cMenuSetup::Set(void)
Add(new cMenuEditIntItem( tr("PrimaryLimit"), &data.PrimaryLimit, 0, MAXPRIORITY));
Add(new cMenuEditIntItem( tr("DefaultPriority"), &data.DefaultPriority, 0, MAXPRIORITY));
Add(new cMenuEditIntItem( tr("DefaultLifetime"), &data.DefaultLifetime, 0, MAXLIFETIME));
+ Add(new cMenuEditBoolItem(tr("UseSubtitle"), &data.UseSubtitle));
Add(new cMenuEditBoolItem(tr("VideoFormat"), &data.VideoFormat, "4:3", "16:9"));
Add(new cMenuEditBoolItem(tr("ChannelInfoPos"), &data.ChannelInfoPos, tr("bottom"), tr("top")));
Add(new cMenuEditIntItem( tr("OSDwidth"), &data.OSDwidth, MINOSDWIDTH, MAXOSDWIDTH));
Add(new cMenuEditIntItem( tr("OSDheight"), &data.OSDheight, MINOSDHEIGHT, MAXOSDHEIGHT));
+ Add(new cMenuEditIntItem( tr("OSDMessageTime"), &data.OSDMessageTime, 1, 60));
Add(new cMenuEditIntItem( tr("MaxVideoFileSize"), &data.MaxVideoFileSize, MINVIDEOFILESIZE, MAXVIDEOFILESIZE));
+ Add(new cMenuEditIntItem( tr("MinEventTimeout"), &data.MinEventTimeout));
+ Add(new cMenuEditIntItem( tr("MinUserInactivity"), &data.MinUserInactivity));
}
eOSState cMenuSetup::ProcessKey(eKeys Key)
@@ -2096,12 +2090,14 @@ cRecordControl::cRecordControl(cDvbApi *DvbApi, cTimer *Timer)
timer->SetPending(true);
timer->SetRecording(true);
if (Channels.SwitchTo(timer->channel, dvbApi)) {
+ const char *Subtitle = NULL;
+ const char *Summary = NULL;
if (GetEventInfo()) {
- //XXX this is in preparation for storing recordings in subdirectories and giving them the name of the Subtitle
- dsyslog(LOG_INFO, "Title: '%s' Subtitle: '%s'", eventInfo->GetTitle(), eventInfo->GetSubtitle());//XXX
- //XXX modify timer's name and summary, mark it as modified (revert later when stopping)
+ dsyslog(LOG_INFO, "Title: '%s' Subtitle: '%s'", eventInfo->GetTitle(), eventInfo->GetSubtitle());
+ Subtitle = eventInfo->GetSubtitle();
+ Summary = eventInfo->GetExtendedDescription();
}
- cRecording Recording(timer);
+ cRecording Recording(timer, Subtitle, Summary);
if (dvbApi->StartRecord(Recording.FileName(), Channels.GetByNumber(timer->channel)->ca, timer->priority))
Recording.WriteSummary();
Interface->DisplayRecording(dvbApi->CardIndex(), true);
@@ -2161,9 +2157,9 @@ void cRecordControl::Stop(bool KeepInstant)
}
}
-bool cRecordControl::Process(void)
+bool cRecordControl::Process(time_t t)
{
- if (!timer || !timer->Matches())
+ if (!timer || !timer->Matches(t))
return false;
AssertFreeDiskSpace(timer->priority);
return true;
@@ -2233,11 +2229,11 @@ const char *cRecordControls::GetInstantId(const char *LastInstantId)
return NULL;
}
-void cRecordControls::Process(void)
+void cRecordControls::Process(time_t t)
{
for (int i = 0; i < MAXDVBAPI; i++) {
if (RecordControls[i]) {
- if (!RecordControls[i]->Process())
+ if (!RecordControls[i]->Process(t))
DELETENULL(RecordControls[i]);
}
}
diff --git a/menu.h b/menu.h
index d6db002..2c5ed39 100644
--- a/menu.h
+++ b/menu.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: menu.h 1.24 2001/08/18 10:22:43 kls Exp $
+ * $Id: menu.h 1.25 2001/09/01 14:52:48 kls Exp $
*/
#ifndef _MENU_H
@@ -78,7 +78,7 @@ private:
public:
cRecordControl(cDvbApi *DvbApi, cTimer *Timer = NULL);
virtual ~cRecordControl();
- bool Process(void);
+ bool Process(time_t t);
bool Uses(cDvbApi *DvbApi) { return DvbApi == dvbApi; }
void Stop(bool KeepInstant = false);
bool IsInstant(void) { return instantId; }
@@ -93,7 +93,7 @@ public:
static void Stop(const char *InstantId);
static void Stop(cDvbApi *DvbApi);
static const char *GetInstantId(const char *LastInstantId);
- static void Process(void);
+ static void Process(time_t t);
static bool Active(void);
};
diff --git a/recording.c b/recording.c
index 0190d10..f657378 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.33 2001/08/12 15:09:59 kls Exp $
+ * $Id: recording.c 1.36 2001/09/02 15:09:28 kls Exp $
*/
#define _GNU_SOURCE
@@ -179,6 +179,7 @@ void cResumeFile::Delete(void)
struct tCharExchange { char a; char b; };
tCharExchange CharExchange[] = {
+ { '~', '/' },
{ ' ', '_' },
{ '\'', '\x01' },
{ '/', '\x02' },
@@ -190,24 +191,45 @@ tCharExchange CharExchange[] = {
char *ExchangeChars(char *s, bool ToFileSystem)
{
- for (struct tCharExchange *ce = CharExchange; ce->a && ce->b; ce++)
- strreplace(s, ToFileSystem ? ce->a : ce->b, ToFileSystem ? ce->b : ce->a);
+ char *p = s;
+ while (*p) {
+ for (struct tCharExchange *ce = CharExchange; ce->a && ce->b; ce++) {
+ if (*p == (ToFileSystem ? ce->a : ce->b)) {
+ *p = ToFileSystem ? ce->b : ce->a;
+ break;
+ }
+ }
+ p++;
+ }
return s;
}
-cRecording::cRecording(cTimer *Timer)
+cRecording::cRecording(cTimer *Timer, const char *Subtitle, const char *Summary)
{
titleBuffer = NULL;
fileName = NULL;
- name = strdup(Timer->file);
+ if (Timer->IsSingleEvent() || !Setup.UseSubtitle)
+ name = strdup(Timer->file);
+ else {
+ if (isempty(Subtitle))
+ Subtitle = " ";
+ asprintf(&name, "%s~%s", Timer->file, Subtitle);
+ }
// substitute characters that would cause problems in file names:
strreplace(name, '\n', ' ');
- summary = Timer->summary ? strdup(Timer->summary) : NULL;
- if (summary)
- strreplace(summary, '|', '\n');
start = Timer->StartTime();
priority = Timer->priority;
lifetime = Timer->lifetime;
+ // handle summary:
+ summary = !isempty(Timer->summary) ? strdup(Timer->summary) : NULL;
+ if (!summary) {
+ if (isempty(Subtitle))
+ Subtitle = "";
+ if (isempty(Summary))
+ Summary = "";
+ if (*Subtitle || *Summary)
+ asprintf(&summary, "%s%s%s", Subtitle, (*Subtitle && *Summary) ? "\n\n" : "", Summary);
+ }
}
cRecording::cRecording(const char *FileName)
@@ -311,6 +333,17 @@ const char *cRecording::Title(char Delimiter, bool NewIndicator)
return titleBuffer;
}
+const char *cRecording::PrefixFileName(char Prefix)
+{
+ const char *p = PrefixVideoFileName(FileName(), Prefix);
+ if (p) {
+ delete fileName;
+ fileName = strdup(p);
+ return fileName;
+ }
+ return NULL;
+}
+
bool cRecording::WriteSummary(void)
{
if (summary) {
diff --git a/recording.h b/recording.h
index 059133e..e1af3db 100644
--- a/recording.h
+++ b/recording.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: recording.h 1.14 2001/06/02 10:00:25 kls Exp $
+ * $Id: recording.h 1.16 2001/09/02 11:35:56 kls Exp $
*/
#ifndef __RECORDING_H
@@ -39,12 +39,13 @@ public:
time_t start;
int priority;
int lifetime;
- cRecording(cTimer *Timer);
+ cRecording(cTimer *Timer, const char *Subtitle, const char *Summary);
cRecording(const char *FileName);
~cRecording();
const char *FileName(void);
const char *Title(char Delimiter = ' ', bool NewIndicator = false);
const char *Summary(void) { return summary; }
+ const char *PrefixFileName(char Prefix);
bool WriteSummary(void);
bool Delete(void);
// Changes the file name so that it will no longer be visible in the "Recordings" menu
diff --git a/svdrp.c b/svdrp.c
index d3bceec..5f8aad4 100644
--- a/svdrp.c
+++ b/svdrp.c
@@ -10,7 +10,7 @@
* and interact with the Video Disk Recorder - or write a full featured
* graphical interface that sits on top of an SVDRP connection.
*
- * $Id: svdrp.c 1.21 2001/08/12 15:10:16 kls Exp $
+ * $Id: svdrp.c 1.22 2001/09/01 09:50:03 kls Exp $
*/
#define _GNU_SOURCE
@@ -166,6 +166,16 @@ const char *HelpPages[] = {
" Create a new timer. Settings must be in the same format as returned\n"
" by the LSTT command. It is an error if a timer with the same channel,\n"
" day, start and stop time already exists.",
+ "NEXT [ abs | rel ]\n"
+ " Show the next timer event. If no option is given, the output will be\n"
+ " in human readable form. With option 'abs' the absolute time of the next\n"
+ " event will be given as the number of seconds since the epoch (time_t\n"
+ " format), while with option 'rel' the relative time will be given as the\n"
+ " number of seconds from now until the event. If the absolute time given\n"
+ " is smaller than the current time, or if the relative time is less than\n"
+ " zero, this means that the timer is currently recording and has started\n"
+ " at the given time. The first value in the resulting line is the number\n"
+ " of the timer.",
"OVLF <sizex> <sizey> <fbaddr> <bpp> <palette>\n"
" Set the size, address depth and palette of the overlay.",
"OVLG <sizex> <sizey> <posx> <posy>\n"
@@ -737,6 +747,28 @@ void cSVDRP::CmdNEWT(const char *Option)
Reply(501, "Missing timer settings");
}
+void cSVDRP::CmdNEXT(const char *Option)
+{
+ cTimer *t = Timers.GetNextActiveTimer();
+ if (t) {
+ time_t Start = t->StartTime();
+ int Number = t->Index() + 1;
+ if (!*Option) {
+ char *s = ctime(&Start);
+ s[strlen(s) - 1] = 0; // strip trailing newline
+ Reply(250, "%d %s", Number, s);
+ }
+ else if (strcasecmp(Option, "ABS") == 0)
+ Reply(250, "%d %ld", Number, Start);
+ else if (strcasecmp(Option, "REL") == 0)
+ Reply(250, "%d %ld", Number, Start - time(NULL));
+ else
+ Reply(501, "Unknown option: \"%s\"", Option);
+ }
+ else
+ Reply(550, "No active timers");
+}
+
void cSVDRP::CmdOVLF(const char *Option)
{
if (*Option) {
@@ -893,6 +925,7 @@ void cSVDRP::Execute(char *Cmd)
else if (CMD("MOVT")) CmdMOVT(s);
else if (CMD("NEWC")) CmdNEWC(s);
else if (CMD("NEWT")) CmdNEWT(s);
+ else if (CMD("NEXT")) CmdNEXT(s);
else if (CMD("OVLF")) CmdOVLF(s);
else if (CMD("OVLG")) CmdOVLG(s);
else if (CMD("OVLC")) CmdOVLC(s);
diff --git a/svdrp.h b/svdrp.h
index 8382708..503439a 100644
--- a/svdrp.h
+++ b/svdrp.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: svdrp.h 1.9 2001/04/01 15:05:38 kls Exp $
+ * $Id: svdrp.h 1.10 2001/09/01 09:24:50 kls Exp $
*/
#ifndef __SVDRP_H
@@ -56,6 +56,7 @@ private:
void CmdMOVT(const char *Option);
void CmdNEWC(const char *Option);
void CmdNEWT(const char *Option);
+ void CmdNEXT(const char *Option);
void CmdOVLF(const char *Option);
void CmdOVLG(const char *Option);
void CmdOVLC(const char *Option);
diff --git a/vdr.c b/vdr.c
index 3f8f8da..efb5e1c 100644
--- a/vdr.c
+++ b/vdr.c
@@ -22,9 +22,10 @@
*
* The project's page is at http://www.cadsoft.de/people/kls/vdr
*
- * $Id: vdr.c 1.64 2001/08/26 15:02:00 kls Exp $
+ * $Id: vdr.c 1.68 2001/09/01 14:50:40 kls Exp $
*/
+#define _GNU_SOURCE
#include <getopt.h>
#include <signal.h>
#include <stdlib.h>
@@ -48,13 +49,16 @@
#endif
#define ACTIVITYTIMEOUT 60 // seconds before starting housekeeping
+#define SHUTDOWNWAIT 300 // seconds to wait in user prompt before automatic shutdown
static int Interrupted = 0;
static void SignalHandler(int signum)
{
- if (signum != SIGPIPE)
+ if (signum != SIGPIPE) {
Interrupted = signum;
+ Interface->Interrupt();
+ }
signal(signum, SignalHandler);
}
@@ -77,7 +81,8 @@ int main(int argc, char *argv[])
const char *ConfigDirectory = NULL;
bool DaemonMode = false;
int WatchdogTimeout = DEFAULTWATCHDOG;
- char *Terminal = NULL;
+ const char *Terminal = NULL;
+ const char *Shutdown = NULL;
static struct option long_options[] = {
{ "audio", required_argument, NULL, 'a' },
@@ -88,16 +93,17 @@ int main(int argc, char *argv[])
{ "help", no_argument, NULL, 'h' },
{ "log", required_argument, NULL, 'l' },
{ "port", required_argument, NULL, 'p' },
+ { "shutdown", required_argument, NULL, 's' },
+ { "terminal", required_argument, NULL, 't' },
{ "video", required_argument, NULL, 'v' },
{ "dvd", required_argument, NULL, 'V' },
{ "watchdog", required_argument, NULL, 'w' },
- { "terminal", required_argument, NULL, 't' },
{ NULL }
};
int c;
int option_index = 0;
- while ((c = getopt_long(argc, argv, "a:c:dD:E:hl:p:t:v:V:w:", long_options, &option_index)) != -1) {
+ while ((c = getopt_long(argc, argv, "a:c:dD:E:hl:p:s:t:v:V:w:", long_options, &option_index)) != -1) {
switch (c) {
case 'a': cDvbApi::SetAudioCommand(optarg);
break;
@@ -134,6 +140,7 @@ int main(int argc, char *argv[])
" 2 = errors and info, 3 = errors, info and debug\n"
" -p PORT, --port=PORT use PORT for SVDRP (default: %d)\n"
" 0 turns off SVDRP\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 DEV, --dvd=DEV use DEV as the DVD device (default: %s)\n"
@@ -170,6 +177,8 @@ int main(int argc, char *argv[])
return 2;
}
break;
+ case 's': Shutdown = optarg;
+ break;
case 't': Terminal = optarg;
break;
case 'v': VideoDirectory = optarg;
@@ -292,8 +301,9 @@ int main(int argc, char *argv[])
cReplayControl *ReplayControl = NULL;
int LastChannel = -1;
int PreviousChannel = cDvbApi::CurrentChannel();
- time_t LastActivity = time(NULL);
+ time_t LastActivity = 0;
int MaxLatencyTime = 0;
+ bool ForceShutdown = false;
if (WatchdogTimeout > 0) {
dsyslog(LOG_INFO, "setting watchdog timer to %d seconds", WatchdogTimeout);
@@ -323,18 +333,21 @@ int main(int argc, char *argv[])
}
// Timers and Recordings:
if (!Menu) {
- cTimer *Timer = Timers.GetMatch();
+ time_t Now = time(NULL); // must do both following calls with the exact same time!
+ cRecordControls::Process(Now);
+ cTimer *Timer = Timers.GetMatch(Now);
if (Timer) {
if (!cRecordControls::Start(Timer))
Timer->SetPending(true);
}
- cRecordControls::Process();
}
// User Input:
cOsdBase **Interact = Menu ? &Menu : (cOsdBase **)&ReplayControl;
eKeys key = Interface->GetKey(!*Interact || !(*Interact)->NeedsFastResponse());
- if (NORMALKEY(key) != kNone)
+ if (NORMALKEY(key) != kNone) {
EITScanner.Activity();
+ LastActivity = time(NULL);
+ }
if (*Interact) {
switch ((*Interact)->ProcessKey(key)) {
case osMenu: DELETENULL(Menu);
@@ -383,39 +396,50 @@ int main(int argc, char *argv[])
break;
// Direct Channel Select:
case k1 ... k9:
- if (!Interface->Recording())
- Menu = new cDisplayChannel(key);
+ Menu = new cDisplayChannel(key);
break;
// Left/Right rotates trough channel groups:
case kLeft|k_Repeat:
case kLeft:
case kRight|k_Repeat:
- case kRight: if (!Interface->Recording()) {
- int SaveGroup = CurrentGroup;
- if (NORMALKEY(key) == kRight)
- CurrentGroup = Channels.GetNextGroup(CurrentGroup) ;
- else
- CurrentGroup = Channels.GetPrevGroup(CurrentGroup < 1 ? 1 : CurrentGroup);
- if (CurrentGroup < 0)
- CurrentGroup = SaveGroup;
- Menu = new cDisplayChannel(CurrentGroup, false, true);
- }
- break;
+ case kRight: {
+ int SaveGroup = CurrentGroup;
+ if (NORMALKEY(key) == kRight)
+ CurrentGroup = Channels.GetNextGroup(CurrentGroup) ;
+ else
+ CurrentGroup = Channels.GetPrevGroup(CurrentGroup < 1 ? 1 : CurrentGroup);
+ if (CurrentGroup < 0)
+ CurrentGroup = SaveGroup;
+ Menu = new cDisplayChannel(CurrentGroup, false, true);
+ break;
+ }
// Up/Down Channel Select:
case kUp|k_Repeat:
case kUp:
case kDown|k_Repeat:
- case kDown: if (!Interface->Recording()) {
- int n = cDvbApi::CurrentChannel() + (NORMALKEY(key) == kUp ? 1 : -1);
- cChannel *channel = Channels.GetByNumber(n);
- if (channel)
- channel->Switch();
- }
- break;
+ case kDown: {
+ int n = cDvbApi::CurrentChannel() + (NORMALKEY(key) == kUp ? 1 : -1);
+ cChannel *channel = Channels.GetByNumber(n);
+ if (channel)
+ channel->Switch();
+ break;
+ }
// Menu Control:
case kMenu: Menu = new cMenuMain(ReplayControl); break;
// Viewing Control:
case kOk: LastChannel = -1; break; // forces channel display
+ // Power off:
+ case kPower: isyslog(LOG_INFO, "Power button pressed");
+ if (!Shutdown) {
+ Interface->Error(tr("Can't shutdown - option '-s' not given!"));
+ break;
+ }
+ if (cRecordControls::Active()) {
+ if (Interface->Confirm(tr("Recording - shut down anyway?")))
+ ForceShutdown = true;
+ }
+ LastActivity = 1; // not 0, see below!
+ break;
default: break;
}
}
@@ -423,14 +447,46 @@ int main(int argc, char *argv[])
EITScanner.Process();
cVideoCutter::Active();
}
- if (!*Interact && !cRecordControls::Active()) {
- if (time(NULL) - LastActivity > ACTIVITYTIMEOUT) {
+ if (!*Interact && (!cRecordControls::Active() || ForceShutdown)) {
+ time_t Now = time(NULL);
+ if (Now - LastActivity > ACTIVITYTIMEOUT) {
+ // Shutdown:
+ if (Shutdown && (Setup.MinUserInactivity && Now - LastActivity > Setup.MinUserInactivity * 60 || ForceShutdown)) {
+ ForceShutdown = false;
+ cTimer *timer = Timers.GetNextActiveTimer();
+ time_t Next = timer ? timer->StartTime() : 0;
+ time_t Delta = timer ? Next - Now : 0;
+ if (timer)
+ dsyslog(LOG_INFO, "next timer event at %s", ctime(&Next));
+ if (!Next || Delta > Setup.MinEventTimeout * 60) {
+ if (!LastActivity) {
+ // Apparently the user started VDR manually
+ dsyslog(LOG_INFO, "assuming manual start of VDR");
+ LastActivity = Now;
+ continue; // skip the rest of the housekeeping for now
+ }
+ if (WatchdogTimeout > 0)
+ signal(SIGALRM, SIG_IGN);
+ if (Interface->Confirm(tr("Press any key to cancel shutdown"), LastActivity == 1 ? 5 : SHUTDOWNWAIT, true)) {
+ char *cmd;
+ asprintf(&cmd, "%s %ld %ld", Shutdown, Next, Delta);
+ isyslog(LOG_INFO, "executing '%s'", cmd);
+ system(cmd);
+ delete cmd;
+ }
+ else if (WatchdogTimeout > 0) {
+ alarm(WatchdogTimeout);
+ if (signal(SIGALRM, Watchdog) == SIG_IGN)
+ signal(SIGALRM, SIG_IGN);
+ }
+ LastActivity = Now; // don't try again too soon
+ continue; // skip the rest of the housekeeping for now
+ }
+ }
+ // Disk housekeeping:
RemoveDeletedRecordings();
- LastActivity = time(NULL);
}
}
- else
- LastActivity = time(NULL);
}
if (Interrupted)
isyslog(LOG_INFO, "caught signal %d", Interrupted);
diff --git a/videodir.c b/videodir.c
index 6f35a3d..d9d3f85 100644
--- a/videodir.c
+++ b/videodir.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: videodir.c 1.5 2001/05/01 09:48:57 kls Exp $
+ * $Id: videodir.c 1.6 2001/09/02 14:55:15 kls Exp $
*/
#include "videodir.h"
@@ -188,13 +188,21 @@ const char *PrefixVideoFileName(const char *FileName, char Prefix)
if (!PrefixedName || strlen(PrefixedName) <= strlen(FileName))
PrefixedName = (char *)realloc(PrefixedName, strlen(FileName) + 2);
if (PrefixedName) {
- strcpy(PrefixedName, VideoDirectory);
- char *p = PrefixedName + strlen(PrefixedName);
- *p++ = '/';
- *p++ = Prefix;
- strcpy(p, FileName + strlen(VideoDirectory) + 1);
+ const char *p = FileName + strlen(FileName); // p points at the terminating 0
+ int n = 2;
+ while (p-- > FileName && n > 0) {
+ if (*p == '/') {
+ if (--n == 0) {
+ int l = p - FileName + 1;
+ strncpy(PrefixedName, FileName, l);
+ PrefixedName[l] = Prefix;
+ strcpy(PrefixedName + l + 1, p + 1);
+ return PrefixedName;
+ }
+ }
+ }
}
- return PrefixedName;
+ return NULL;
}
void RemoveEmptyVideoDirectories(void)