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.
This commit is contained in:
Klaus Schmidinger 2001-09-02 18:00:00 +02:00
parent ae8fe25312
commit bb18b9e0b4
21 changed files with 456 additions and 187 deletions

View File

@ -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)

39
HISTORY
View File

@ -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.

52
INSTALL
View File

@ -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

34
MANUAL
View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

74
i18n.c
View File

@ -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",

View File

@ -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 (;;) {

View File

@ -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);

Binary file not shown.

View File

@ -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

38
menu.c
View File

@ -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]);
}
}

6
menu.h
View File

@ -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);
};

View File

@ -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) {

View File

@ -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

35
svdrp.c
View File

@ -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);

View File

@ -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);

124
vdr.c
View File

@ -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);

View File

@ -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)