mirror of
https://github.com/VDR4Arch/vdr.git
synced 2023-10-10 13:36:52 +02:00
Implemented VPS controlled timers
This commit is contained in:
parent
4063d72760
commit
198fcf437b
26
HISTORY
26
HISTORY
@ -2652,7 +2652,7 @@ Video Disk Recorder Revision History
|
|||||||
actual CAM type as reported by the CAM. The 'ca.conf' file has been stripped
|
actual CAM type as reported by the CAM. The 'ca.conf' file has been stripped
|
||||||
down to the values 0..4.
|
down to the values 0..4.
|
||||||
|
|
||||||
2004-02-23: Version 1.3.5
|
2004-02-29: Version 1.3.5
|
||||||
|
|
||||||
- Fixed reading the EPG preferred language parameter from 'setup.conf'.
|
- Fixed reading the EPG preferred language parameter from 'setup.conf'.
|
||||||
- Fixed switching to a visible programme in case the current channel has neither
|
- Fixed switching to a visible programme in case the current channel has neither
|
||||||
@ -2680,11 +2680,8 @@ Video Disk Recorder Revision History
|
|||||||
channel won't interrupt an ongoing Transfer Mode.
|
channel won't interrupt an ongoing Transfer Mode.
|
||||||
- Added subtable ID and TSDT handling to 'libsi' (thanks to Marcel Wiesweg).
|
- Added subtable ID and TSDT handling to 'libsi' (thanks to Marcel Wiesweg).
|
||||||
- Fixed some Russian OSD texts (thanks to Vyacheslav Dikonov).
|
- Fixed some Russian OSD texts (thanks to Vyacheslav Dikonov).
|
||||||
- Added the 'running status' to the EPG events. This might lead to a VPS like
|
- Added the 'running status' to the EPG events. This is necessary for implementing
|
||||||
function for recording, but unfortunately not all stations handle this flag
|
the VPS function for recording.
|
||||||
correctly - and some (like RTL, for instance) even change the ID of the same
|
|
||||||
event randomly, making it impossible for a timer to be programmed on a ceartain
|
|
||||||
event rather than a specific time. Well, let's see where this leads us...
|
|
||||||
- Removed the obsolete 'present' and 'following' handling from the EPG data.
|
- Removed the obsolete 'present' and 'following' handling from the EPG data.
|
||||||
- The EPG data is now always kept sorted chronologically in the internal data
|
- The EPG data is now always kept sorted chronologically in the internal data
|
||||||
structures. This also means that any EPG data retrieved through the SVRDP
|
structures. This also means that any EPG data retrieved through the SVRDP
|
||||||
@ -2698,10 +2695,21 @@ Video Disk Recorder Revision History
|
|||||||
still displayed in the "Schedule" menu (thanks to Jaakko Hyvätti).
|
still displayed in the "Schedule" menu (thanks to Jaakko Hyvätti).
|
||||||
- Added PDCDescriptor handling to 'libsi'.
|
- Added PDCDescriptor handling to 'libsi'.
|
||||||
- Implemented handling the VPS timestamps (aka "Programme Identification Label")
|
- Implemented handling the VPS timestamps (aka "Programme Identification Label")
|
||||||
in preparation for full VPS support for timers (provided the tv stations
|
for full VPS support for timers (provided the tv stations actually broadcast
|
||||||
actually broadcast this information). Currently these are just displayed in
|
this information). The VPS time is displayed in the event info page if it exists
|
||||||
the event page if they exist and are different than the event's start time.
|
and is different than the event's start time.
|
||||||
- Extended the SVDRP command LSTE to allow limiting the listed data to a given
|
- Extended the SVDRP command LSTE to allow limiting the listed data to a given
|
||||||
channel, the present or following events, or events at a given time (thanks to
|
channel, the present or following events, or events at a given time (thanks to
|
||||||
Thomas Heiligenmann).
|
Thomas Heiligenmann).
|
||||||
- Fixed a typo in libsi/si.h (thanks to Stéphane Esté-Gracias).
|
- Fixed a typo in libsi/si.h (thanks to Stéphane Esté-Gracias).
|
||||||
|
- Timers can now be set to use the VPS information to control recording a programme.
|
||||||
|
The new setup options "Recording/Use VPS" and "Recording/VPS margin", as well as
|
||||||
|
the "VPS" option in the individual timers, can be used to control this feature
|
||||||
|
(see MANUAL for details).
|
||||||
|
Note that this feature will certainly need a lot of testing before it can be
|
||||||
|
called "safe"!
|
||||||
|
- The "Schedule" and "What's on now/next?" menus now have an additional column
|
||||||
|
which displays information on whether there is a timer defined for an event,
|
||||||
|
whether an event has a VPS time that's different than its start time, and
|
||||||
|
whether an event is currently running (see MANUAL under "The "Schedule" Menu"
|
||||||
|
for details).
|
||||||
|
29
MANUAL
29
MANUAL
@ -138,6 +138,16 @@ Version 1.2
|
|||||||
The "Blue" button can be pressed to switch to the channel with the selected
|
The "Blue" button can be pressed to switch to the channel with the selected
|
||||||
programme.
|
programme.
|
||||||
|
|
||||||
|
The following markers in these menus give additional information about the
|
||||||
|
status of the events:
|
||||||
|
|
||||||
|
t there is a timer defined for this event which covers only part of the event
|
||||||
|
T there is a timer defined for this event which covers the entire event
|
||||||
|
V this event has a VPS time that's different than its start time
|
||||||
|
* this event is currently running (the validity of this marker depends on
|
||||||
|
whether there is currently a DVB card receiving the transponder this channel
|
||||||
|
is on).
|
||||||
|
|
||||||
* Selecting a Channel
|
* Selecting a Channel
|
||||||
|
|
||||||
There are four ways to select a channel:
|
There are four ways to select a channel:
|
||||||
@ -351,6 +361,14 @@ Version 1.2
|
|||||||
would have a Day setting of "M-W----".
|
would have a Day setting of "M-W----".
|
||||||
Start: The start time of the timer in hh:mm as 24 hour ("military") time.
|
Start: The start time of the timer in hh:mm as 24 hour ("military") time.
|
||||||
Stop: The stop time of the timer.
|
Stop: The stop time of the timer.
|
||||||
|
VPS: Defines whether the timer shall use VPS (if available). If this
|
||||||
|
option is set to 'yes', the start time must exactly match the
|
||||||
|
programme's VPS time, otherwise nothing will be recorded. If VPS
|
||||||
|
is used, the stop time has no real meaning. However, it must be
|
||||||
|
different than the start time, and should correspond to the actual
|
||||||
|
stop time of the programme, just in case there is no real VPS data
|
||||||
|
available at the time of recording, so VDR has to fall back to
|
||||||
|
normal timer recording.
|
||||||
Priority: The Priority (0..99) is used to decide which timer shall be
|
Priority: The Priority (0..99) is used to decide which timer shall be
|
||||||
started in case there are two or more timers with the exact same
|
started in case there are two or more timers with the exact same
|
||||||
start time. The first timer in the list with the highest Priority
|
start time. The first timer in the list with the highest Priority
|
||||||
@ -585,6 +603,17 @@ Version 1.2
|
|||||||
no = don't use the 'Episode name'
|
no = don't use the 'Episode name'
|
||||||
yes = use it (and create subdirectories)
|
yes = use it (and create subdirectories)
|
||||||
|
|
||||||
|
Use VPS = 0 Defines whether a timer that is created from an EPG entry
|
||||||
|
(by pressing the "Record" (red) button in the "Schedules"
|
||||||
|
or "What's on now/next?" menu) will automatically use VPS
|
||||||
|
if the event it is created for has a VPS time.
|
||||||
|
|
||||||
|
VPS margin = 120 Defines how many seconds before a VPS controlled timer is
|
||||||
|
scheduled to start, VDR will make sure that one of the DVB
|
||||||
|
devices is tuned to the transponder that timer shall record
|
||||||
|
from. This is necessary for the "Running Status" information
|
||||||
|
that is broadcast in the EPG data to be seen by VDR.
|
||||||
|
|
||||||
Mark instant recording = yes
|
Mark instant recording = yes
|
||||||
Defines whether an "instant recording" (started by
|
Defines whether an "instant recording" (started by
|
||||||
pressing the "Red" button in the "VDR" menu) will be
|
pressing the "Red" button in the "VDR" menu) will be
|
||||||
|
130
README.vps
Normal file
130
README.vps
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
VPS (Video Programming Service)
|
||||||
|
===============================
|
||||||
|
|
||||||
|
Beginning with version 1.3.5 VDR supports the VPS method
|
||||||
|
of identifying programmes to record, and making sure they
|
||||||
|
are recorded in full length, even if they run longer than
|
||||||
|
initially specified or are shifted in time.
|
||||||
|
|
||||||
|
Of course, the main prerequisite for this to work is that
|
||||||
|
the broadcasters actually provide the necessary data. In
|
||||||
|
particular these are
|
||||||
|
|
||||||
|
- EPG data (well, obviously)
|
||||||
|
- the data for each event must contain the "Programme Identification Label"
|
||||||
|
descriptor, which contains the VPS timestamp for this programme
|
||||||
|
- the event data must provide and maintain the "Running Status" flag,
|
||||||
|
which indicates whether this programme is currently running or not.
|
||||||
|
|
||||||
|
Currently only the German "Öffentlich Rechtliche" tv stations provide
|
||||||
|
the necessary VPS data, so this will work only for stations like "Das Erste",
|
||||||
|
"ZDF" and the like.
|
||||||
|
|
||||||
|
Following is a step by step description of what happens for a VPS controlled
|
||||||
|
timer recording. First let's take a look at what the VDR user needs to do.
|
||||||
|
|
||||||
|
VPS as seen by the VDR user:
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
When the VDR user sets up a timer that shall be under VPS control, there
|
||||||
|
are only two things that need to be done:
|
||||||
|
|
||||||
|
1. Set the "Start" time to the actual VPS time as published in tv magazines.
|
||||||
|
Typically the VPS time is the same as the printed start time, unless
|
||||||
|
expliciltly specified otherwise. For instance, a tv magazine might print
|
||||||
|
|
||||||
|
20:15 Wetten, dass...?
|
||||||
|
(VPS = 20:14)
|
||||||
|
|
||||||
|
In this case the timer would need to be set to 20:14.
|
||||||
|
|
||||||
|
2. Set the "VPS" flag in the timer definition to "yes" in order to tell VDR
|
||||||
|
that this timer is to be handled under VPS control. This is no different
|
||||||
|
to old analog video recorders, where each timer has also had a separate
|
||||||
|
VPS flag.
|
||||||
|
|
||||||
|
If the user sets up a timer from the "Schedule" menu, things are even simpler.
|
||||||
|
If the setup option "Recording/Use VPS" is set to "yes", any timer that is
|
||||||
|
programmed from an event that has VPS information will automatically be set
|
||||||
|
up as a VPS timer.
|
||||||
|
|
||||||
|
IMPORTANT: In order for a recording to work under VPS control it is of
|
||||||
|
========== paramount importance that the start time is set to the actual
|
||||||
|
VPS time of that event, NOT some time a few minutes before the
|
||||||
|
event starts! If a timer is set to use VPS, and the time doesn't
|
||||||
|
match any event's VPS time, nothing will be recorded!
|
||||||
|
|
||||||
|
VPS as seen by VDR:
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
The following things happen when VDR processes timers:
|
||||||
|
|
||||||
|
- VDR regularly scans the EPG data and assigns events to the timers (see
|
||||||
|
cTimers::SetEvents() in VDR/timers.c).
|
||||||
|
This can be seen in the log file as
|
||||||
|
|
||||||
|
timer 1 (15 1830-1900 'Neues') set to event 28.02.2004 18:30-18:59 (VPS: 28.02 18:30) 'neues'
|
||||||
|
|
||||||
|
- When a VPS timer is asked whether it matches (i.e. whether a recording shall
|
||||||
|
be started), it checks whether it has an event assigned to it, and whether
|
||||||
|
that event has a running status of "starts in a few seconds" or "running"
|
||||||
|
(see cTimer::Matches(time_t t, bool Directly) in VDR/timers.c). This allows
|
||||||
|
the recording process to catch the entire programme, even if it runs longer
|
||||||
|
than initially advertised. It also works if it runs shorter or gets shifted.
|
||||||
|
|
||||||
|
- When a VPS timer event is coming up (i.e. there are only a few minutes until
|
||||||
|
it starts, according to the related event data's start time - which may be
|
||||||
|
different than the VPS time!), VDR tunes a free DVB device to that transponder
|
||||||
|
(unless there is already a device tuned to that one) in order to make sure
|
||||||
|
that the event data (especially the "Running Status") will be up to date and
|
||||||
|
a change in the "Running status" flag will be seen immediately. This may
|
||||||
|
lead to the primary device being switched to a different channel if there
|
||||||
|
is no other free DVB device available. See the main program loop in VDR/vdr.c,
|
||||||
|
"Make sure VPS timers "see" their channel early enough:".
|
||||||
|
|
||||||
|
Problems:
|
||||||
|
---------
|
||||||
|
|
||||||
|
- In order for a VPS controlled timer to function properly, it needs to "see"
|
||||||
|
any changes in the running status of its event. This means that one of the
|
||||||
|
DVB devices needs to be tuned to the proper transponder some time before
|
||||||
|
the actual start time of the event. However, this may result in an other
|
||||||
|
timer (with lower priority) to be stopped, because it occupies the DVB device
|
||||||
|
and has it tuned to a different transponder.
|
||||||
|
See "// Make sure VPS timers "see" their channel early enough:" in VDR/vdr.c.
|
||||||
|
TODO:
|
||||||
|
Something needs to be done to prevent two timers from repeatedly switching
|
||||||
|
the device between channels in such a situation.
|
||||||
|
|
||||||
|
- If, for some reason, the driver doesn't deliver any more section data, a
|
||||||
|
VPS controlled timer will never see that the programme has started (or ended).
|
||||||
|
TODO:
|
||||||
|
Therefore some mechanism needs to be implemented that makes absolutely sure
|
||||||
|
we continuously receive at least the event data for the present event.
|
||||||
|
|
||||||
|
Caveats:
|
||||||
|
--------
|
||||||
|
|
||||||
|
Apparently VPS in digital broadcasting is still in an early state. Only few
|
||||||
|
tv stations actually support it, and other tv stations don't even handle the
|
||||||
|
"Running Status" correctly (which, by itself, would already be helpful, even
|
||||||
|
without VPS).
|
||||||
|
|
||||||
|
Here's a list of things that are apparently done wrong by the individual
|
||||||
|
stations:
|
||||||
|
|
||||||
|
- The German "Öffentlich Rechtliche" tv stations, although supporting VPS,
|
||||||
|
don't switch the "Running Status" of an upcoming broadcast to "starts in
|
||||||
|
a few seconds", but rather go directly from "unknown" or "not running" to
|
||||||
|
"running". This may result in a recording that misses the first few seconds
|
||||||
|
of the programme.
|
||||||
|
- The RTL group handles EPG events in a rather random way. They change event
|
||||||
|
IDs randomly, and switch the "Running Status" flag at times that are only
|
||||||
|
losely related to the actual events. For instance, if the "RTL aktuell"
|
||||||
|
programme starts at 18:45, they switch that event to "running" at about
|
||||||
|
18:43. Or, even worse, if "Wer wird Millionär?" runs until 21:15, they
|
||||||
|
switch the _next_ programme to running (which implicitly set "Wer wird
|
||||||
|
Millionär?" to "not running) at around 21:11 - so anybody using that
|
||||||
|
information to control recording would not see the end of that programme.
|
||||||
|
|
||||||
|
... more following as it comes up...
|
8
config.c
8
config.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: config.c 1.124 2004/02/21 15:05:40 kls Exp $
|
* $Id: config.c 1.125 2004/02/28 11:12:20 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@ -272,6 +272,8 @@ cSetup::cSetup(void)
|
|||||||
PausePriority = 10;
|
PausePriority = 10;
|
||||||
PauseLifetime = 1;
|
PauseLifetime = 1;
|
||||||
UseSubtitle = 1;
|
UseSubtitle = 1;
|
||||||
|
UseVps = 0;
|
||||||
|
VpsMargin = 120;
|
||||||
RecordingDirs = 1;
|
RecordingDirs = 1;
|
||||||
VideoFormat = 0;
|
VideoFormat = 0;
|
||||||
UpdateChannels = 4;
|
UpdateChannels = 4;
|
||||||
@ -417,6 +419,8 @@ bool cSetup::Parse(const char *Name, const char *Value)
|
|||||||
else if (!strcasecmp(Name, "PausePriority")) PausePriority = atoi(Value);
|
else if (!strcasecmp(Name, "PausePriority")) PausePriority = atoi(Value);
|
||||||
else if (!strcasecmp(Name, "PauseLifetime")) PauseLifetime = atoi(Value);
|
else if (!strcasecmp(Name, "PauseLifetime")) PauseLifetime = atoi(Value);
|
||||||
else if (!strcasecmp(Name, "UseSubtitle")) UseSubtitle = atoi(Value);
|
else if (!strcasecmp(Name, "UseSubtitle")) UseSubtitle = atoi(Value);
|
||||||
|
else if (!strcasecmp(Name, "UseVps")) UseVps = atoi(Value);
|
||||||
|
else if (!strcasecmp(Name, "VpsMargin")) VpsMargin = atoi(Value);
|
||||||
else if (!strcasecmp(Name, "RecordingDirs")) RecordingDirs = atoi(Value);
|
else if (!strcasecmp(Name, "RecordingDirs")) RecordingDirs = atoi(Value);
|
||||||
else if (!strcasecmp(Name, "VideoFormat")) VideoFormat = atoi(Value);
|
else if (!strcasecmp(Name, "VideoFormat")) VideoFormat = atoi(Value);
|
||||||
else if (!strcasecmp(Name, "UpdateChannels")) UpdateChannels = atoi(Value);
|
else if (!strcasecmp(Name, "UpdateChannels")) UpdateChannels = atoi(Value);
|
||||||
@ -469,6 +473,8 @@ bool cSetup::Save(void)
|
|||||||
Store("PausePriority", PausePriority);
|
Store("PausePriority", PausePriority);
|
||||||
Store("PauseLifetime", PauseLifetime);
|
Store("PauseLifetime", PauseLifetime);
|
||||||
Store("UseSubtitle", UseSubtitle);
|
Store("UseSubtitle", UseSubtitle);
|
||||||
|
Store("UseVps", UseVps);
|
||||||
|
Store("VpsMargin", VpsMargin);
|
||||||
Store("RecordingDirs", RecordingDirs);
|
Store("RecordingDirs", RecordingDirs);
|
||||||
Store("VideoFormat", VideoFormat);
|
Store("VideoFormat", VideoFormat);
|
||||||
Store("UpdateChannels", UpdateChannels);
|
Store("UpdateChannels", UpdateChannels);
|
||||||
|
4
config.h
4
config.h
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: config.h 1.188 2004/02/21 15:04:53 kls Exp $
|
* $Id: config.h 1.189 2004/02/28 11:11:35 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __CONFIG_H
|
#ifndef __CONFIG_H
|
||||||
@ -228,6 +228,8 @@ public:
|
|||||||
int DefaultPriority, DefaultLifetime;
|
int DefaultPriority, DefaultLifetime;
|
||||||
int PausePriority, PauseLifetime;
|
int PausePriority, PauseLifetime;
|
||||||
int UseSubtitle;
|
int UseSubtitle;
|
||||||
|
int UseVps;
|
||||||
|
int VpsMargin;
|
||||||
int RecordingDirs;
|
int RecordingDirs;
|
||||||
int VideoFormat;
|
int VideoFormat;
|
||||||
int UpdateChannels;
|
int UpdateChannels;
|
||||||
|
14
epg.c
14
epg.c
@ -7,11 +7,12 @@
|
|||||||
* Original version (as used in VDR before 1.3.0) written by
|
* Original version (as used in VDR before 1.3.0) written by
|
||||||
* Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
|
* Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
|
||||||
*
|
*
|
||||||
* $Id: epg.c 1.13 2004/02/22 14:41:37 kls Exp $
|
* $Id: epg.c 1.14 2004/02/29 13:48:34 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "epg.h"
|
#include "epg.h"
|
||||||
#include "libsi/si.h"
|
#include "libsi/si.h"
|
||||||
|
#include "timers.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
@ -95,6 +96,15 @@ void cEvent::SetVps(time_t Vps)
|
|||||||
vps = Vps;
|
vps = Vps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool cEvent::HasTimer(void) const
|
||||||
|
{
|
||||||
|
for (cTimer *t = Timers.First(); t; t = Timers.Next(t)) {
|
||||||
|
if (t->Event() == this)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const char *cEvent::GetDateString(void) const
|
const char *cEvent::GetDateString(void) const
|
||||||
{
|
{
|
||||||
static char buf[25];
|
static char buf[25];
|
||||||
@ -545,7 +555,7 @@ void cSchedule::Cleanup(time_t Time)
|
|||||||
Event = events.Get(a);
|
Event = events.Get(a);
|
||||||
if (!Event)
|
if (!Event)
|
||||||
break;
|
break;
|
||||||
if (Event->StartTime() + Event->Duration() + Setup.EPGLinger * 60 + 3600 < Time) { // adding one hour for safety
|
if (!Event->HasTimer() && Event->StartTime() + Event->Duration() + Setup.EPGLinger * 60 + 3600 < Time) { // adding one hour for safety
|
||||||
events.Del(Event);
|
events.Del(Event);
|
||||||
a--;
|
a--;
|
||||||
}
|
}
|
||||||
|
3
epg.h
3
epg.h
@ -7,7 +7,7 @@
|
|||||||
* Original version (as used in VDR before 1.3.0) written by
|
* Original version (as used in VDR before 1.3.0) written by
|
||||||
* Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
|
* Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
|
||||||
*
|
*
|
||||||
* $Id: epg.h 1.10 2004/02/22 14:34:04 kls Exp $
|
* $Id: epg.h 1.11 2004/02/29 14:10:06 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __EPG_H
|
#ifndef __EPG_H
|
||||||
@ -51,6 +51,7 @@ public:
|
|||||||
time_t StartTime(void) const { return startTime; }
|
time_t StartTime(void) const { return startTime; }
|
||||||
int Duration(void) const { return duration; }
|
int Duration(void) const { return duration; }
|
||||||
time_t Vps(void) const { return vps; }
|
time_t Vps(void) const { return vps; }
|
||||||
|
bool HasTimer(void) const;
|
||||||
const char *GetDateString(void) const;
|
const char *GetDateString(void) const;
|
||||||
const char *GetTimeString(void) const;
|
const char *GetTimeString(void) const;
|
||||||
const char *GetEndTimeString(void) const;
|
const char *GetEndTimeString(void) const;
|
||||||
|
56
i18n.c
56
i18n.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: i18n.c 1.148 2004/02/21 15:14:36 kls Exp $
|
* $Id: i18n.c 1.149 2004/02/28 11:13:27 kls Exp $
|
||||||
*
|
*
|
||||||
* Translations provided by:
|
* Translations provided by:
|
||||||
*
|
*
|
||||||
@ -1542,6 +1542,24 @@ const tI18nPhrase Phrases[] = {
|
|||||||
"Fi",
|
"Fi",
|
||||||
"ºÞÝÕæ",
|
"ºÞÝÕæ",
|
||||||
},
|
},
|
||||||
|
{ "VPS",
|
||||||
|
"VPS",
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
},
|
||||||
{ "Priority",
|
{ "Priority",
|
||||||
"Priorität",
|
"Priorität",
|
||||||
"Prioriteta",
|
"Prioriteta",
|
||||||
@ -2805,6 +2823,42 @@ const tI18nPhrase Phrases[] = {
|
|||||||
"Utilitzar el nom de l'episodi",
|
"Utilitzar el nom de l'episodi",
|
||||||
"³àãßßØàÞÒÐâì äÐÙÛë ßÞ íßØ×ÞÔÐÜ",
|
"³àãßßØàÞÒÐâì äÐÙÛë ßÞ íßØ×ÞÔÐÜ",
|
||||||
},
|
},
|
||||||
|
{ "Setup.Recording$Use VPS",
|
||||||
|
"VPS benutzen",
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
},
|
||||||
|
{ "Setup.Recording$VPS margin (s)",
|
||||||
|
"Zeitpuffer bei VPS (s)",
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
"",// TODO
|
||||||
|
},
|
||||||
{ "Setup.Recording$Mark instant recording",
|
{ "Setup.Recording$Mark instant recording",
|
||||||
"Direktaufzeichnung markieren",
|
"Direktaufzeichnung markieren",
|
||||||
"Oznaci direktno snemanje",
|
"Oznaci direktno snemanje",
|
||||||
|
53
menu.c
53
menu.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: menu.c 1.292 2004/02/22 14:14:55 kls Exp $
|
* $Id: menu.c 1.293 2004/02/29 14:11:16 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "menu.h"
|
#include "menu.h"
|
||||||
@ -18,6 +18,7 @@
|
|||||||
#include "cutter.h"
|
#include "cutter.h"
|
||||||
#include "eitscan.h"
|
#include "eitscan.h"
|
||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
|
#include "libsi/si.h"
|
||||||
#include "menuitems.h"
|
#include "menuitems.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
#include "recording.h"
|
#include "recording.h"
|
||||||
@ -871,13 +872,14 @@ cMenuEditTimer::cMenuEditTimer(cTimer *Timer, bool New)
|
|||||||
if (timer) {
|
if (timer) {
|
||||||
data = *timer;
|
data = *timer;
|
||||||
if (New)
|
if (New)
|
||||||
data.active = 1;
|
data.SetFlags(tfActive);
|
||||||
channel = data.Channel()->Number();
|
channel = data.Channel()->Number();
|
||||||
Add(new cMenuEditBoolItem(tr("Active"), &data.active));
|
Add(new cMenuEditBitItem( tr("Active"), &data.flags, tfActive));
|
||||||
Add(new cMenuEditChanItem(tr("Channel"), &channel));
|
Add(new cMenuEditChanItem(tr("Channel"), &channel));
|
||||||
Add(new cMenuEditDayItem( tr("Day"), &data.day));
|
Add(new cMenuEditDayItem( tr("Day"), &data.day));
|
||||||
Add(new cMenuEditTimeItem(tr("Start"), &data.start));
|
Add(new cMenuEditTimeItem(tr("Start"), &data.start));
|
||||||
Add(new cMenuEditTimeItem(tr("Stop"), &data.stop));
|
Add(new cMenuEditTimeItem(tr("Stop"), &data.stop));
|
||||||
|
Add(new cMenuEditBitItem( tr("VPS"), &data.flags, tfVps));
|
||||||
Add(new cMenuEditIntItem( tr("Priority"), &data.priority, 0, MAXPRIORITY));
|
Add(new cMenuEditIntItem( tr("Priority"), &data.priority, 0, MAXPRIORITY));
|
||||||
Add(new cMenuEditIntItem( tr("Lifetime"), &data.lifetime, 0, MAXLIFETIME));
|
Add(new cMenuEditIntItem( tr("Lifetime"), &data.lifetime, 0, MAXLIFETIME));
|
||||||
Add(new cMenuEditStrItem( tr("File"), data.file, sizeof(data.file), tr(FileNameChars)));
|
Add(new cMenuEditStrItem( tr("File"), data.file, sizeof(data.file), tr(FileNameChars)));
|
||||||
@ -926,13 +928,13 @@ eOSState cMenuEditTimer::ProcessKey(eKeys Key)
|
|||||||
if (timer) {
|
if (timer) {
|
||||||
if (memcmp(timer, &data, sizeof(data)) != 0) {
|
if (memcmp(timer, &data, sizeof(data)) != 0) {
|
||||||
*timer = data;
|
*timer = data;
|
||||||
if (timer->active)
|
if (timer->HasFlags(tfActive))
|
||||||
timer->active = 1; // allows external programs to mark active timers with values > 1 and recognize if the user has modified them
|
timer->ClrFlags(~tfAll); // allows external programs to mark active timers with values > 0xFFFF and recognize if the user has modified them
|
||||||
}
|
}
|
||||||
if (addIfConfirmed)
|
if (addIfConfirmed)
|
||||||
Timers.Add(timer);
|
Timers.Add(timer);
|
||||||
Timers.Save();
|
Timers.Save();
|
||||||
isyslog("timer %d %s (%s)", timer->Index() + 1, addIfConfirmed ? "added" : "modified", timer->active ? "active" : "inactive");
|
isyslog("timer %d %s (%s)", timer->Index() + 1, addIfConfirmed ? "added" : "modified", timer->HasFlags(tfActive) ? "active" : "inactive");
|
||||||
addIfConfirmed = false;
|
addIfConfirmed = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -976,7 +978,7 @@ void cMenuTimerItem::Set(void)
|
|||||||
{
|
{
|
||||||
char *buffer = NULL;
|
char *buffer = NULL;
|
||||||
asprintf(&buffer, "%c\t%d\t%s\t%02d:%02d\t%02d:%02d\t%s",
|
asprintf(&buffer, "%c\t%d\t%s\t%02d:%02d\t%02d:%02d\t%s",
|
||||||
!timer->Active() ? ' ' : timer->FirstDay() ? '!' : timer->Recording() ? '#' : '>',
|
!(timer->HasFlags(tfActive)) ? ' ' : timer->FirstDay() ? '!' : timer->Recording() ? '#' : '>',
|
||||||
timer->Channel()->Number(),
|
timer->Channel()->Number(),
|
||||||
timer->PrintDay(timer->Day()),
|
timer->PrintDay(timer->Day()),
|
||||||
timer->Start() / 100,
|
timer->Start() / 100,
|
||||||
@ -1041,7 +1043,7 @@ eOSState cMenuTimers::OnOff(void)
|
|||||||
if (timer->FirstDay())
|
if (timer->FirstDay())
|
||||||
isyslog("timer %d first day set to %s", timer->Index() + 1, timer->PrintFirstDay());
|
isyslog("timer %d first day set to %s", timer->Index() + 1, timer->PrintFirstDay());
|
||||||
else
|
else
|
||||||
isyslog("timer %d %sactivated", timer->Index() + 1, timer->Active() ? "" : "de");
|
isyslog("timer %d %sactivated", timer->Index() + 1, timer->HasFlags(tfActive) ? "" : "de");
|
||||||
Timers.Save();
|
Timers.Save();
|
||||||
}
|
}
|
||||||
return osContinue;
|
return osContinue;
|
||||||
@ -1211,7 +1213,11 @@ cMenuWhatsOnItem::cMenuWhatsOnItem(const cEvent *Event, cChannel *Channel)
|
|||||||
event = Event;
|
event = Event;
|
||||||
channel = Channel;
|
channel = Channel;
|
||||||
char *buffer = NULL;
|
char *buffer = NULL;
|
||||||
asprintf(&buffer, "%d\t%.*s\t%.*s\t%s", channel->Number(), 6, channel->Name(), 5, event->GetTimeString(), event->Title());
|
int TimerMatch;
|
||||||
|
char t = Timers.GetMatch(Event, &TimerMatch) ? (TimerMatch == tmFull) ? 'T' : 't' : ' ';
|
||||||
|
char v = event->Vps() && (event->Vps() - event->StartTime()) ? 'V' : ' ';
|
||||||
|
char r = event->RunningStatus() > SI::RunningStatusNotRunning ? '*' : ' ';
|
||||||
|
asprintf(&buffer, "%d\t%.*s\t%.*s\t%c%c%c\t%s", channel->Number(), 6, channel->Name(), 5, event->GetTimeString(), t, v, r, event->Title());
|
||||||
SetText(buffer, false);
|
SetText(buffer, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1235,7 +1241,7 @@ int cMenuWhatsOn::currentChannel = 0;
|
|||||||
const cEvent *cMenuWhatsOn::scheduleEvent = NULL;
|
const cEvent *cMenuWhatsOn::scheduleEvent = NULL;
|
||||||
|
|
||||||
cMenuWhatsOn::cMenuWhatsOn(const cSchedules *Schedules, bool Now, int CurrentChannelNr)
|
cMenuWhatsOn::cMenuWhatsOn(const cSchedules *Schedules, bool Now, int CurrentChannelNr)
|
||||||
:cOsdMenu(Now ? tr("What's on now?") : tr("What's on next?"), CHNUMWIDTH, 7, 6)
|
:cOsdMenu(Now ? tr("What's on now?") : tr("What's on next?"), CHNUMWIDTH, 7, 6, 4)
|
||||||
{
|
{
|
||||||
for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) {
|
for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) {
|
||||||
if (!Channel->GroupSep()) {
|
if (!Channel->GroupSep()) {
|
||||||
@ -1325,7 +1331,11 @@ cMenuScheduleItem::cMenuScheduleItem(const cEvent *Event)
|
|||||||
{
|
{
|
||||||
event = Event;
|
event = Event;
|
||||||
char *buffer = NULL;
|
char *buffer = NULL;
|
||||||
asprintf(&buffer, "%.*s\t%.*s\t%s", 5, event->GetDateString(), 5, event->GetTimeString(), event->Title());
|
int TimerMatch;
|
||||||
|
char t = Timers.GetMatch(Event, &TimerMatch) ? (TimerMatch == tmFull) ? 'T' : 't' : ' ';
|
||||||
|
char v = event->Vps() && (event->Vps() - event->StartTime()) ? 'V' : ' ';
|
||||||
|
char r = event->RunningStatus() > SI::RunningStatusNotRunning ? '*' : ' ';
|
||||||
|
asprintf(&buffer, "%.*s\t%.*s\t%c%c%c\t%s", 5, event->GetDateString(), 5, event->GetTimeString(), t, v, r, event->Title());
|
||||||
SetText(buffer, false);
|
SetText(buffer, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1347,7 +1357,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
cMenuSchedule::cMenuSchedule(void)
|
cMenuSchedule::cMenuSchedule(void)
|
||||||
:cOsdMenu("", 6, 6)
|
:cOsdMenu("", 6, 6, 4)
|
||||||
{
|
{
|
||||||
now = next = false;
|
now = next = false;
|
||||||
otherChannel = 0;
|
otherChannel = 0;
|
||||||
@ -2294,6 +2304,8 @@ cMenuSetupRecord::cMenuSetupRecord(void)
|
|||||||
Add(new cMenuEditIntItem( tr("Setup.Recording$Pause priority"), &data.PausePriority, 0, MAXPRIORITY));
|
Add(new cMenuEditIntItem( tr("Setup.Recording$Pause priority"), &data.PausePriority, 0, MAXPRIORITY));
|
||||||
Add(new cMenuEditIntItem( tr("Setup.Recording$Pause lifetime (d)"), &data.PauseLifetime, 0, MAXLIFETIME));
|
Add(new cMenuEditIntItem( tr("Setup.Recording$Pause lifetime (d)"), &data.PauseLifetime, 0, MAXLIFETIME));
|
||||||
Add(new cMenuEditBoolItem(tr("Setup.Recording$Use episode name"), &data.UseSubtitle));
|
Add(new cMenuEditBoolItem(tr("Setup.Recording$Use episode name"), &data.UseSubtitle));
|
||||||
|
Add(new cMenuEditBoolItem(tr("Setup.Recording$Use VPS"), &data.UseVps));
|
||||||
|
Add(new cMenuEditIntItem( tr("Setup.Recording$VPS margin (s)"), &data.VpsMargin, 0));
|
||||||
Add(new cMenuEditBoolItem(tr("Setup.Recording$Mark instant recording"), &data.MarkInstantRecord));
|
Add(new cMenuEditBoolItem(tr("Setup.Recording$Mark instant recording"), &data.MarkInstantRecord));
|
||||||
Add(new cMenuEditStrItem( tr("Setup.Recording$Name instant recording"), data.NameInstantRecord, sizeof(data.NameInstantRecord), tr(FileNameChars)));
|
Add(new cMenuEditStrItem( tr("Setup.Recording$Name instant recording"), data.NameInstantRecord, sizeof(data.NameInstantRecord), tr(FileNameChars)));
|
||||||
Add(new cMenuEditIntItem( tr("Setup.Recording$Instant rec. time (min)"), &data.InstantRecordTime, 1, MAXINSTANTRECTIME));
|
Add(new cMenuEditIntItem( tr("Setup.Recording$Instant rec. time (min)"), &data.InstantRecordTime, 1, MAXINSTANTRECTIME));
|
||||||
@ -3056,11 +3068,12 @@ cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer, bool Pause)
|
|||||||
}
|
}
|
||||||
timer->SetPending(true);
|
timer->SetPending(true);
|
||||||
timer->SetRecording(true);
|
timer->SetRecording(true);
|
||||||
|
event = timer->Event();
|
||||||
|
|
||||||
const char *Title = NULL;
|
const char *Title = NULL;
|
||||||
const char *Subtitle = NULL;
|
const char *Subtitle = NULL;
|
||||||
const char *Summary = NULL;
|
const char *Summary = NULL;
|
||||||
if (GetEvent()) {
|
if (event || GetEvent()) {
|
||||||
Title = event->Title();
|
Title = event->Title();
|
||||||
Subtitle = event->ShortText();
|
Subtitle = event->ShortText();
|
||||||
Summary = event->Description();
|
Summary = event->Description();
|
||||||
@ -3115,7 +3128,7 @@ cRecordControl::~cRecordControl()
|
|||||||
bool cRecordControl::GetEvent(void)
|
bool cRecordControl::GetEvent(void)
|
||||||
{
|
{
|
||||||
const cChannel *channel = timer->Channel();
|
const cChannel *channel = timer->Channel();
|
||||||
time_t Time = timer->Active() == taActInst ? timer->StartTime() + INSTANT_REC_EPG_LOOKAHEAD : timer->StartTime() + (timer->StopTime() - timer->StartTime()) / 2;
|
time_t Time = timer->HasFlags(tfInstant) ? timer->StartTime() + INSTANT_REC_EPG_LOOKAHEAD : timer->StartTime() + (timer->StopTime() - timer->StartTime()) / 2;
|
||||||
for (int seconds = 0; seconds <= MAXWAIT4EPGINFO; seconds++) {
|
for (int seconds = 0; seconds <= MAXWAIT4EPGINFO; seconds++) {
|
||||||
{
|
{
|
||||||
cSchedulesLock SchedulesLock;
|
cSchedulesLock SchedulesLock;
|
||||||
@ -3187,12 +3200,14 @@ bool cRecordControls::Start(cTimer *Timer, bool Pause)
|
|||||||
cThread::EmergencyExit(true);
|
cThread::EmergencyExit(true);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < MAXRECORDCONTROLS; i++) {
|
if (!Timer || Timer->Matches()) {
|
||||||
if (!RecordControls[i]) {
|
for (int i = 0; i < MAXRECORDCONTROLS; i++) {
|
||||||
RecordControls[i] = new cRecordControl(device, Timer, Pause);
|
if (!RecordControls[i]) {
|
||||||
return true;
|
RecordControls[i] = new cRecordControl(device, Timer, Pause);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!Timer || (Timer->Priority() >= Setup.PrimaryLimit && !Timer->Pending()))
|
else if (!Timer || (Timer->Priority() >= Setup.PrimaryLimit && !Timer->Pending()))
|
||||||
isyslog("no free DVB device to record channel %d!", ch);
|
isyslog("no free DVB device to record channel %d!", ch);
|
||||||
|
19
menuitems.c
19
menuitems.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: menuitems.c 1.14 2004/01/25 15:40:55 kls Exp $
|
* $Id: menuitems.c 1.15 2004/02/24 12:38:43 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "menuitems.h"
|
#include "menuitems.h"
|
||||||
@ -113,6 +113,23 @@ void cMenuEditBoolItem::Set(void)
|
|||||||
SetValue(buf);
|
SetValue(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- cMenuEditBitItem ------------------------------------------------------
|
||||||
|
|
||||||
|
cMenuEditBitItem::cMenuEditBitItem(const char *Name, int *Value, int Mask, const char *FalseString, const char *TrueString)
|
||||||
|
:cMenuEditBoolItem(Name, &bit, FalseString, TrueString)
|
||||||
|
{
|
||||||
|
value = Value;
|
||||||
|
bit = (*value & Mask) != 0;
|
||||||
|
mask = Mask;
|
||||||
|
Set();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cMenuEditBitItem::Set(void)
|
||||||
|
{
|
||||||
|
*value = bit ? *value | mask : *value & ~mask;
|
||||||
|
cMenuEditBoolItem::Set();
|
||||||
|
}
|
||||||
|
|
||||||
// --- cMenuEditNumItem ------------------------------------------------------
|
// --- cMenuEditNumItem ------------------------------------------------------
|
||||||
|
|
||||||
cMenuEditNumItem::cMenuEditNumItem(const char *Name, char *Value, int Length, bool Blind)
|
cMenuEditNumItem::cMenuEditNumItem(const char *Name, char *Value, int Length, bool Blind)
|
||||||
|
12
menuitems.h
12
menuitems.h
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: menuitems.h 1.5 2003/01/12 15:06:23 kls Exp $
|
* $Id: menuitems.h 1.6 2004/02/24 11:55:14 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __MENUITEMS_H
|
#ifndef __MENUITEMS_H
|
||||||
@ -42,6 +42,16 @@ public:
|
|||||||
cMenuEditBoolItem(const char *Name, int *Value, const char *FalseString = NULL, const char *TrueString = NULL);
|
cMenuEditBoolItem(const char *Name, int *Value, const char *FalseString = NULL, const char *TrueString = NULL);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class cMenuEditBitItem : public cMenuEditBoolItem {
|
||||||
|
protected:
|
||||||
|
int *value;
|
||||||
|
int bit;
|
||||||
|
int mask;
|
||||||
|
virtual void Set(void);
|
||||||
|
public:
|
||||||
|
cMenuEditBitItem(const char *Name, int *Value, int Mask, const char *FalseString = NULL, const char *TrueString = NULL);
|
||||||
|
};
|
||||||
|
|
||||||
class cMenuEditNumItem : public cMenuEditItem {
|
class cMenuEditNumItem : public cMenuEditItem {
|
||||||
protected:
|
protected:
|
||||||
char *value;
|
char *value;
|
||||||
|
8
svdrp.c
8
svdrp.c
@ -10,7 +10,7 @@
|
|||||||
* and interact with the Video Disk Recorder - or write a full featured
|
* and interact with the Video Disk Recorder - or write a full featured
|
||||||
* graphical interface that sits on top of an SVDRP connection.
|
* graphical interface that sits on top of an SVDRP connection.
|
||||||
*
|
*
|
||||||
* $Id: svdrp.c 1.60 2004/02/22 15:31:23 kls Exp $
|
* $Id: svdrp.c 1.61 2004/02/24 12:24:43 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "svdrp.h"
|
#include "svdrp.h"
|
||||||
@ -905,16 +905,16 @@ void cSVDRP::CmdMODT(const char *Option)
|
|||||||
if (timer) {
|
if (timer) {
|
||||||
cTimer t = *timer;
|
cTimer t = *timer;
|
||||||
if (strcasecmp(tail, "ON") == 0)
|
if (strcasecmp(tail, "ON") == 0)
|
||||||
t.SetActive(taActive);
|
t.SetFlags(tfActive);
|
||||||
else if (strcasecmp(tail, "OFF") == 0)
|
else if (strcasecmp(tail, "OFF") == 0)
|
||||||
t.SetActive(taInactive);
|
t.ClrFlags(tfActive);
|
||||||
else if (!t.Parse(tail)) {
|
else if (!t.Parse(tail)) {
|
||||||
Reply(501, "Error in timer settings");
|
Reply(501, "Error in timer settings");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
*timer = t;
|
*timer = t;
|
||||||
Timers.Save();
|
Timers.Save();
|
||||||
isyslog("timer %d modified (%s)", timer->Index() + 1, timer->Active() ? "active" : "inactive");
|
isyslog("timer %d modified (%s)", timer->Index() + 1, timer->HasFlags(tfActive) ? "active" : "inactive");
|
||||||
Reply(250, "%d %s", timer->Index() + 1, timer->ToText());
|
Reply(250, "%d %s", timer->Index() + 1, timer->ToText());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
161
timers.c
161
timers.c
@ -4,13 +4,14 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: timers.c 1.9 2004/02/13 15:37:49 kls Exp $
|
* $Id: timers.c 1.10 2004/02/29 14:20:48 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "timers.h"
|
#include "timers.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include "channels.h"
|
#include "channels.h"
|
||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
|
#include "libsi/si.h"
|
||||||
|
|
||||||
// IMPORTANT NOTE: in the 'sscanf()' calls there is a blank after the '%d'
|
// IMPORTANT NOTE: in the 'sscanf()' calls there is a blank after the '%d'
|
||||||
// format characters in order to allow any number of blanks after a numeric
|
// format characters in order to allow any number of blanks after a numeric
|
||||||
@ -23,8 +24,10 @@ char *cTimer::buffer = NULL;
|
|||||||
cTimer::cTimer(bool Instant, bool Pause)
|
cTimer::cTimer(bool Instant, bool Pause)
|
||||||
{
|
{
|
||||||
startTime = stopTime = 0;
|
startTime = stopTime = 0;
|
||||||
recording = pending = false;
|
recording = pending = inVpsMargin = false;
|
||||||
active = Instant ? taActInst : taInactive;
|
flags = tfNone;
|
||||||
|
if (Instant)
|
||||||
|
SetFlags(tfActive | tfInstant);
|
||||||
channel = Channels.GetByNumber(cDevice::CurrentChannel());
|
channel = Channels.GetByNumber(cDevice::CurrentChannel());
|
||||||
time_t t = time(NULL);
|
time_t t = time(NULL);
|
||||||
struct tm tm_r;
|
struct tm tm_r;
|
||||||
@ -40,6 +43,7 @@ cTimer::cTimer(bool Instant, bool Pause)
|
|||||||
*file = 0;
|
*file = 0;
|
||||||
firstday = 0;
|
firstday = 0;
|
||||||
summary = NULL;
|
summary = NULL;
|
||||||
|
event = NULL;
|
||||||
if (Instant && channel)
|
if (Instant && channel)
|
||||||
snprintf(file, sizeof(file), "%s%s", Setup.MarkInstantRecord ? "@" : "", *Setup.NameInstantRecord ? Setup.NameInstantRecord : channel->Name());
|
snprintf(file, sizeof(file), "%s%s", Setup.MarkInstantRecord ? "@" : "", *Setup.NameInstantRecord ? Setup.NameInstantRecord : channel->Name());
|
||||||
}
|
}
|
||||||
@ -47,12 +51,17 @@ cTimer::cTimer(bool Instant, bool Pause)
|
|||||||
cTimer::cTimer(const cEvent *Event)
|
cTimer::cTimer(const cEvent *Event)
|
||||||
{
|
{
|
||||||
startTime = stopTime = 0;
|
startTime = stopTime = 0;
|
||||||
recording = pending = false;
|
recording = pending = inVpsMargin = false;
|
||||||
active = true;
|
flags = tfActive;
|
||||||
|
if (Event->Vps() && Setup.UseVps)
|
||||||
|
SetFlags(tfVps);
|
||||||
channel = Channels.GetByChannelID(Event->ChannelID(), true);
|
channel = Channels.GetByChannelID(Event->ChannelID(), true);
|
||||||
time_t tstart = Event->StartTime();
|
time_t tstart = (flags & tfVps) ? Event->Vps() : Event->StartTime();
|
||||||
time_t tstop = tstart + Event->Duration() + Setup.MarginStop * 60;
|
time_t tstop = tstart + Event->Duration();
|
||||||
tstart -= Setup.MarginStart * 60;
|
if (!(HasFlags(tfVps))) {
|
||||||
|
tstop += Setup.MarginStop * 60;
|
||||||
|
tstart -= Setup.MarginStart * 60;
|
||||||
|
}
|
||||||
struct tm tm_r;
|
struct tm tm_r;
|
||||||
struct tm *time = localtime_r(&tstart, &tm_r);
|
struct tm *time = localtime_r(&tstart, &tm_r);
|
||||||
day = time->tm_mday;
|
day = time->tm_mday;
|
||||||
@ -69,6 +78,7 @@ cTimer::cTimer(const cEvent *Event)
|
|||||||
strn0cpy(file, Event->Title(), sizeof(file));
|
strn0cpy(file, Event->Title(), sizeof(file));
|
||||||
firstday = 0;
|
firstday = 0;
|
||||||
summary = NULL;
|
summary = NULL;
|
||||||
|
event = Event;
|
||||||
}
|
}
|
||||||
|
|
||||||
cTimer::~cTimer()
|
cTimer::~cTimer()
|
||||||
@ -81,6 +91,7 @@ cTimer& cTimer::operator= (const cTimer &Timer)
|
|||||||
memcpy(this, &Timer, sizeof(*this));
|
memcpy(this, &Timer, sizeof(*this));
|
||||||
if (summary)
|
if (summary)
|
||||||
summary = strdup(summary);
|
summary = strdup(summary);
|
||||||
|
event = NULL;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,7 +108,7 @@ const char *cTimer::ToText(bool UseChannelID)
|
|||||||
free(buffer);
|
free(buffer);
|
||||||
strreplace(file, ':', '|');
|
strreplace(file, ':', '|');
|
||||||
strreplace(summary, '\n', '|');
|
strreplace(summary, '\n', '|');
|
||||||
asprintf(&buffer, "%d:%s:%s:%04d:%04d:%d:%d:%s:%s\n", active, UseChannelID ? Channel()->GetChannelID().ToString() : itoa(Channel()->Number()), PrintDay(day, firstday), start, stop, priority, lifetime, file, summary ? summary : "");
|
asprintf(&buffer, "%d:%s:%s:%04d:%04d:%d:%d:%s:%s\n", flags, UseChannelID ? Channel()->GetChannelID().ToString() : itoa(Channel()->Number()), PrintDay(day, firstday), start, stop, priority, lifetime, file, summary ? summary : "");
|
||||||
strreplace(summary, '|', '\n');
|
strreplace(summary, '|', '\n');
|
||||||
strreplace(file, '|', ':');
|
strreplace(file, '|', ':');
|
||||||
return buffer;
|
return buffer;
|
||||||
@ -205,7 +216,7 @@ bool cTimer::Parse(const char *s)
|
|||||||
s = s2;
|
s = s2;
|
||||||
}
|
}
|
||||||
bool result = false;
|
bool result = false;
|
||||||
if (8 <= sscanf(s, "%d :%a[^:]:%a[^:]:%d :%d :%d :%d :%a[^:\n]:%a[^\n]", &active, &channelbuffer, &daybuffer, &start, &stop, &priority, &lifetime, &filebuffer, &summary)) {
|
if (8 <= sscanf(s, "%d :%a[^:]:%a[^:]:%d :%d :%d :%d :%a[^:\n]:%a[^\n]", &flags, &channelbuffer, &daybuffer, &start, &stop, &priority, &lifetime, &filebuffer, &summary)) {
|
||||||
if (summary && !*skipspace(summary)) {
|
if (summary && !*skipspace(summary)) {
|
||||||
free(summary);
|
free(summary);
|
||||||
summary = NULL;
|
summary = NULL;
|
||||||
@ -290,7 +301,7 @@ char *cTimer::SetFile(const char *File)
|
|||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cTimer::Matches(time_t t)
|
bool cTimer::Matches(time_t t, bool Directly)
|
||||||
{
|
{
|
||||||
startTime = stopTime = 0;
|
startTime = stopTime = 0;
|
||||||
if (t == 0)
|
if (t == 0)
|
||||||
@ -316,9 +327,35 @@ bool cTimer::Matches(time_t t)
|
|||||||
}
|
}
|
||||||
if (!startTime)
|
if (!startTime)
|
||||||
startTime = firstday; // just to have something that's more than a week in the future
|
startTime = firstday; // just to have something that's more than a week in the future
|
||||||
else if (t > startTime || t > firstday + SECSINDAY + 3600) // +3600 in case of DST change
|
else if (!Directly && (t > startTime || t > firstday + SECSINDAY + 3600)) // +3600 in case of DST change
|
||||||
firstday = 0;
|
firstday = 0;
|
||||||
return active && startTime <= t && t < stopTime; // must stop *before* stopTime to allow adjacent timers
|
|
||||||
|
if (HasFlags(tfActive)) {
|
||||||
|
if (HasFlags(tfVps) && !Directly && event && event->Vps()) {
|
||||||
|
startTime = event->StartTime();
|
||||||
|
stopTime = startTime + event->Duration();
|
||||||
|
return event->RunningStatus() > SI::RunningStatusNotRunning;
|
||||||
|
}
|
||||||
|
return startTime <= t && t < stopTime; // must stop *before* stopTime to allow adjacent timers
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cTimer::Matches(const cEvent *Event)
|
||||||
|
{
|
||||||
|
if (channel->GetChannelID() == Event->ChannelID()) {
|
||||||
|
bool UseVps = HasFlags(tfVps) && Event->Vps();
|
||||||
|
time_t t1 = UseVps ? Event->Vps() : Event->StartTime();
|
||||||
|
time_t t2 = t1 + Event->Duration();
|
||||||
|
bool m1 = Matches(t1, true);
|
||||||
|
bool m2 = UseVps ? m1 : Matches(t2, true);
|
||||||
|
startTime = stopTime = 0;
|
||||||
|
if (m1 && m2)
|
||||||
|
return tmFull;
|
||||||
|
if (m1 || m2)
|
||||||
|
return tmPartial;
|
||||||
|
}
|
||||||
|
return tmNone;
|
||||||
}
|
}
|
||||||
|
|
||||||
time_t cTimer::StartTime(void)
|
time_t cTimer::StartTime(void)
|
||||||
@ -335,6 +372,19 @@ time_t cTimer::StopTime(void)
|
|||||||
return stopTime;
|
return stopTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cTimer::SetEvent(const cEvent *Event)
|
||||||
|
{
|
||||||
|
if (event != Event) { //XXX TODO check event data, too???
|
||||||
|
if (Event) {
|
||||||
|
char vpsbuf[64] = "";
|
||||||
|
if (Event->Vps())
|
||||||
|
sprintf(vpsbuf, "(VPS: %s) ", Event->GetVpsString());
|
||||||
|
isyslog("timer %d (%d %04d-%04d '%s') set to event %s %s-%s %s'%s'", Index() + 1, Channel()->Number(), start, stop, file, Event->GetDateString(), Event->GetTimeString(), Event->GetEndTimeString(), vpsbuf, Event->Title());
|
||||||
|
}
|
||||||
|
event = Event;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void cTimer::SetRecording(bool Recording)
|
void cTimer::SetRecording(bool Recording)
|
||||||
{
|
{
|
||||||
recording = Recording;
|
recording = Recording;
|
||||||
@ -346,28 +396,52 @@ void cTimer::SetPending(bool Pending)
|
|||||||
pending = Pending;
|
pending = Pending;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cTimer::SetActive(int Active)
|
void cTimer::SetInVpsMargin(bool InVpsMargin)
|
||||||
{
|
{
|
||||||
active = Active;
|
if (InVpsMargin && !inVpsMargin)
|
||||||
|
isyslog("timer %d (%d %04d-%04d '%s') entered VPS margin", Index() + 1, Channel()->Number(), start, stop, file);
|
||||||
|
inVpsMargin = InVpsMargin;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cTimer::SetFlags(int Flags)
|
||||||
|
{
|
||||||
|
flags |= Flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cTimer::ClrFlags(int Flags)
|
||||||
|
{
|
||||||
|
flags &= ~Flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cTimer::InvFlags(int Flags)
|
||||||
|
{
|
||||||
|
flags ^= Flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cTimer::HasFlags(int Flags)
|
||||||
|
{
|
||||||
|
return (flags & Flags) == Flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cTimer::Skip(void)
|
void cTimer::Skip(void)
|
||||||
{
|
{
|
||||||
firstday = IncDay(SetTime(StartTime(), 0), 1);
|
firstday = IncDay(SetTime(StartTime(), 0), 1);
|
||||||
|
event = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cTimer::OnOff(void)
|
void cTimer::OnOff(void)
|
||||||
{
|
{
|
||||||
if (IsSingleEvent())
|
if (IsSingleEvent())
|
||||||
active = !active;
|
InvFlags(tfActive);
|
||||||
else if (firstday) {
|
else if (firstday) {
|
||||||
firstday = 0;
|
firstday = 0;
|
||||||
active = false;
|
ClrFlags(tfActive);
|
||||||
}
|
}
|
||||||
else if (active)
|
else if (HasFlags(tfActive))
|
||||||
Skip();
|
Skip();
|
||||||
else
|
else
|
||||||
active = true;
|
SetFlags(tfActive);
|
||||||
|
event = NULL;
|
||||||
Matches(); // refresh start and end time
|
Matches(); // refresh start and end time
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -396,12 +470,59 @@ cTimer *cTimers::GetMatch(time_t t)
|
|||||||
return t0;
|
return t0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cTimer *cTimers::GetMatch(const cEvent *Event, int *Match)
|
||||||
|
{
|
||||||
|
cTimer *t = NULL;
|
||||||
|
int m = tmNone;
|
||||||
|
for (cTimer *ti = First(); ti; ti = Next(ti)) {
|
||||||
|
int tm = ti->Matches(Event);
|
||||||
|
if (tm > m) {
|
||||||
|
t = ti;
|
||||||
|
m = tm;
|
||||||
|
if (m == tmFull)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Match)
|
||||||
|
*Match = m;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
cTimer *cTimers::GetNextActiveTimer(void)
|
cTimer *cTimers::GetNextActiveTimer(void)
|
||||||
{
|
{
|
||||||
cTimer *t0 = NULL;
|
cTimer *t0 = NULL;
|
||||||
for (cTimer *ti = First(); ti; ti = Next(ti)) {
|
for (cTimer *ti = First(); ti; ti = Next(ti)) {
|
||||||
if (ti->Active() && (!t0 || *ti < *t0))
|
if ((ti->HasFlags(tfActive)) && (!t0 || *ti < *t0))
|
||||||
t0 = ti;
|
t0 = ti;
|
||||||
}
|
}
|
||||||
return t0;
|
return t0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cTimers::SetEvents(void)
|
||||||
|
{
|
||||||
|
cSchedulesLock SchedulesLock;
|
||||||
|
const cSchedules *Schedules = cSchedules::Schedules(SchedulesLock);
|
||||||
|
if (Schedules) {
|
||||||
|
for (cTimer *ti = First(); ti; ti = Next(ti)) {
|
||||||
|
const cSchedule *Schedule = Schedules->GetSchedule(ti->Channel()->GetChannelID());
|
||||||
|
const cEvent *Event = NULL;
|
||||||
|
if (Schedule) {
|
||||||
|
//XXX what if the Schedule doesn't have any VPS???
|
||||||
|
const cEvent *e;
|
||||||
|
int Match = tmNone;
|
||||||
|
int i = 0;
|
||||||
|
while ((e = Schedule->GetEventNumber(i++)) != NULL) {
|
||||||
|
int m = ti->Matches(e);
|
||||||
|
if (m > Match) {
|
||||||
|
Match = m;
|
||||||
|
Event = e;
|
||||||
|
if (Match == tmFull)
|
||||||
|
break;
|
||||||
|
//XXX what if there's another event with the same VPS time???
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ti->SetEvent(Event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
35
timers.h
35
timers.h
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* how to reach the author.
|
||||||
*
|
*
|
||||||
* $Id: timers.h 1.6 2003/12/13 13:04:21 kls Exp $
|
* $Id: timers.h 1.7 2004/02/29 14:18:17 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __TIMERS_H
|
#ifndef __TIMERS_H
|
||||||
@ -15,19 +15,21 @@
|
|||||||
#include "epg.h"
|
#include "epg.h"
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
|
|
||||||
enum eTimerActive { taInactive = 0,
|
enum eTimerFlags { tfNone = 0x0000,
|
||||||
taActive = 1,
|
tfActive = 0x0001,
|
||||||
taInstant = 2,
|
tfInstant = 0x0002,
|
||||||
taActInst = (taActive | taInstant)
|
tfVps = 0x0004,
|
||||||
};
|
tfAll = 0xFFFF,
|
||||||
|
};
|
||||||
|
enum eTimerMatch { tmNone, tmPartial, tmFull };
|
||||||
|
|
||||||
class cTimer : public cListObject {
|
class cTimer : public cListObject {
|
||||||
friend class cMenuEditTimer;
|
friend class cMenuEditTimer;
|
||||||
private:
|
private:
|
||||||
time_t startTime, stopTime;
|
time_t startTime, stopTime;
|
||||||
static char *buffer;
|
static char *buffer;
|
||||||
bool recording, pending;
|
bool recording, pending, inVpsMargin;
|
||||||
int active;
|
int flags;
|
||||||
cChannel *channel;
|
cChannel *channel;
|
||||||
int day;
|
int day;
|
||||||
int start;
|
int start;
|
||||||
@ -37,6 +39,7 @@ private:
|
|||||||
char file[MaxFileName];
|
char file[MaxFileName];
|
||||||
time_t firstday;
|
time_t firstday;
|
||||||
char *summary;
|
char *summary;
|
||||||
|
const cEvent *event;
|
||||||
public:
|
public:
|
||||||
cTimer(bool Instant = false, bool Pause = false);
|
cTimer(bool Instant = false, bool Pause = false);
|
||||||
cTimer(const cEvent *Event);
|
cTimer(const cEvent *Event);
|
||||||
@ -45,7 +48,8 @@ public:
|
|||||||
virtual bool operator< (const cListObject &ListObject);
|
virtual bool operator< (const cListObject &ListObject);
|
||||||
bool Recording(void) { return recording; }
|
bool Recording(void) { return recording; }
|
||||||
bool Pending(void) { return pending; }
|
bool Pending(void) { return pending; }
|
||||||
int Active(void) { return active; }
|
bool InVpsMargin(void) { return inVpsMargin; }
|
||||||
|
int Flags(void) { return flags; }
|
||||||
const cChannel *Channel(void) { return channel; }
|
const cChannel *Channel(void) { return channel; }
|
||||||
int Day(void) { return day; }
|
int Day(void) { return day; }
|
||||||
int Start(void) { return start; }
|
int Start(void) { return start; }
|
||||||
@ -56,6 +60,7 @@ public:
|
|||||||
time_t FirstDay(void) { return firstday; }
|
time_t FirstDay(void) { return firstday; }
|
||||||
const char *Summary(void) { return summary; }
|
const char *Summary(void) { return summary; }
|
||||||
const char *ToText(bool UseChannelID = false);
|
const char *ToText(bool UseChannelID = false);
|
||||||
|
const cEvent *Event(void) { return event; }
|
||||||
bool Parse(const char *s);
|
bool Parse(const char *s);
|
||||||
bool Save(FILE *f);
|
bool Save(FILE *f);
|
||||||
bool IsSingleEvent(void);
|
bool IsSingleEvent(void);
|
||||||
@ -65,12 +70,18 @@ public:
|
|||||||
static time_t IncDay(time_t t, int Days);
|
static time_t IncDay(time_t t, int Days);
|
||||||
static time_t SetTime(time_t t, int SecondsFromMidnight);
|
static time_t SetTime(time_t t, int SecondsFromMidnight);
|
||||||
char *SetFile(const char *File);
|
char *SetFile(const char *File);
|
||||||
bool Matches(time_t t = 0);
|
bool Matches(time_t t = 0, bool Directly = false);
|
||||||
|
int Matches(const cEvent *Event);
|
||||||
time_t StartTime(void);
|
time_t StartTime(void);
|
||||||
time_t StopTime(void);
|
time_t StopTime(void);
|
||||||
|
void SetEvent(const cEvent *Event);
|
||||||
void SetRecording(bool Recording);
|
void SetRecording(bool Recording);
|
||||||
void SetPending(bool Pending);
|
void SetPending(bool Pending);
|
||||||
void SetActive(int Active);
|
void SetInVpsMargin(bool InVpsMargin);
|
||||||
|
void SetFlags(int Flags);
|
||||||
|
void ClrFlags(int Flags);
|
||||||
|
void InvFlags(int Flags);
|
||||||
|
bool HasFlags(int Flags);
|
||||||
void Skip(void);
|
void Skip(void);
|
||||||
void OnOff(void);
|
void OnOff(void);
|
||||||
const char *PrintFirstDay(void);
|
const char *PrintFirstDay(void);
|
||||||
@ -85,10 +96,12 @@ private:
|
|||||||
public:
|
public:
|
||||||
cTimer *GetTimer(cTimer *Timer);
|
cTimer *GetTimer(cTimer *Timer);
|
||||||
cTimer *GetMatch(time_t t);
|
cTimer *GetMatch(time_t t);
|
||||||
|
cTimer *GetMatch(const cEvent *Event, int *Match = NULL);
|
||||||
cTimer *GetNextActiveTimer(void);
|
cTimer *GetNextActiveTimer(void);
|
||||||
int BeingEdited(void) { return beingEdited; }
|
int BeingEdited(void) { return beingEdited; }
|
||||||
void IncBeingEdited(void) { beingEdited++; }
|
void IncBeingEdited(void) { beingEdited++; }
|
||||||
void DecBeingEdited(void) { beingEdited--; }
|
void DecBeingEdited(void) { beingEdited--; }
|
||||||
|
void SetEvents(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern cTimers Timers;
|
extern cTimers Timers;
|
||||||
|
19
vdr.5
19
vdr.5
@ -8,7 +8,7 @@
|
|||||||
.\" License as specified in the file COPYING that comes with the
|
.\" License as specified in the file COPYING that comes with the
|
||||||
.\" vdr distribution.
|
.\" vdr distribution.
|
||||||
.\"
|
.\"
|
||||||
.\" $Id: vdr.5 1.25 2004/02/22 13:18:48 kls Exp $
|
.\" $Id: vdr.5 1.26 2004/02/24 12:36:35 kls Exp $
|
||||||
.\"
|
.\"
|
||||||
.TH vdr 5 "1 Jun 2003" "1.2.0" "Video Disk Recorder Files"
|
.TH vdr 5 "1 Jun 2003" "1.2.0" "Video Disk Recorder Files"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
@ -196,12 +196,17 @@ The fields in a timer definition have the following meaning (from left
|
|||||||
to right):
|
to right):
|
||||||
.TP
|
.TP
|
||||||
.B Status
|
.B Status
|
||||||
Defines whether this timer is \fBinactive\fR (0) or \fBactive\fR (1).
|
The individual bits in this field have the following meaning:
|
||||||
The value 3 is used for instant recordings.
|
.TS
|
||||||
Values other than these can be used by external programs to mark active timers
|
tab (@);
|
||||||
and recognize if the user has modified them. When a user modifes an active
|
l l.
|
||||||
timer the \fBstatus\fR field will be explicitly set to '1' (or '0', respectively,
|
\fB1\fR@the timer is active (and will record if it hits)
|
||||||
if the user deactivates the timer).
|
\fB2\fR@this is an instant recording timer
|
||||||
|
\fB4\fR@this timer uses VPS
|
||||||
|
.TE
|
||||||
|
Bits other than these can be used by external programs to mark active timers
|
||||||
|
and recognize if the user has modified them. When a user modifies an active
|
||||||
|
timer, the upper 16 bits of this 32 bit parameter will be explicitly set to 0.
|
||||||
|
|
||||||
Note: in order to allow future extensibility, external programs using the
|
Note: in order to allow future extensibility, external programs using the
|
||||||
\fBstatus\fR parameter should only use the upper 16 bit of this 32 bit parameter
|
\fBstatus\fR parameter should only use the upper 16 bit of this 32 bit parameter
|
||||||
|
30
vdr.c
30
vdr.c
@ -22,7 +22,7 @@
|
|||||||
*
|
*
|
||||||
* The project's page is at http://www.cadsoft.de/vdr
|
* The project's page is at http://www.cadsoft.de/vdr
|
||||||
*
|
*
|
||||||
* $Id: vdr.c 1.177 2004/02/15 14:29:30 kls Exp $
|
* $Id: vdr.c 1.178 2004/02/29 14:21:22 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
@ -483,6 +483,7 @@ int main(int argc, char *argv[])
|
|||||||
int MaxLatencyTime = 0;
|
int MaxLatencyTime = 0;
|
||||||
bool ForceShutdown = false;
|
bool ForceShutdown = false;
|
||||||
bool UserShutdown = false;
|
bool UserShutdown = false;
|
||||||
|
bool TimerInVpsMargin = false;
|
||||||
|
|
||||||
while (!Interrupted) {
|
while (!Interrupted) {
|
||||||
// Handle emergency exits:
|
// Handle emergency exits:
|
||||||
@ -548,8 +549,15 @@ int main(int argc, char *argv[])
|
|||||||
PreviousChannel[PreviousChannelIndex ^= 1] = LastChannel;
|
PreviousChannel[PreviousChannelIndex ^= 1] = LastChannel;
|
||||||
// Timers and Recordings:
|
// Timers and Recordings:
|
||||||
if (!Timers.BeingEdited()) {
|
if (!Timers.BeingEdited()) {
|
||||||
time_t Now = time(NULL); // must do both following calls with the exact same time!
|
static time_t LastSetEvents = 0;//XXX trigger by actual EPG data modification???
|
||||||
|
if (!Menu && time(NULL) - LastSetEvents > 5) {
|
||||||
|
Timers.SetEvents();
|
||||||
|
LastSetEvents = time(NULL);
|
||||||
|
}
|
||||||
|
time_t Now = time(NULL); // must do all following calls with the exact same time!
|
||||||
|
// Process ongoing recordings:
|
||||||
cRecordControls::Process(Now);
|
cRecordControls::Process(Now);
|
||||||
|
// Start new recordings:
|
||||||
cTimer *Timer = Timers.GetMatch(Now);
|
cTimer *Timer = Timers.GetMatch(Now);
|
||||||
if (Timer) {
|
if (Timer) {
|
||||||
if (!cRecordControls::Start(Timer))
|
if (!cRecordControls::Start(Timer))
|
||||||
@ -557,6 +565,21 @@ int main(int argc, char *argv[])
|
|||||||
else
|
else
|
||||||
LastTimerChannel = Timer->Channel()->Number();
|
LastTimerChannel = Timer->Channel()->Number();
|
||||||
}
|
}
|
||||||
|
// Make sure VPS timers "see" their channel early enough:
|
||||||
|
TimerInVpsMargin = false;
|
||||||
|
for (cTimer *Timer = Timers.First(); Timer; Timer = Timers.Next(Timer)) {
|
||||||
|
if (Timer->HasFlags(tfActive | tfVps) && !Timer->Recording() && !Timer->Pending() && Timer->Matches(Now + Setup.VpsMargin, true)) {
|
||||||
|
if (!Timer->InVpsMargin()) {
|
||||||
|
Timer->SetInVpsMargin(true);
|
||||||
|
TimerInVpsMargin = true;
|
||||||
|
//XXX if not primary device has TP???
|
||||||
|
LastTimerChannel = Timer->Channel()->Number();
|
||||||
|
cRecordControls::Start(Timer); // will only switch the device
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Timer->SetInVpsMargin(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// CAM control:
|
// CAM control:
|
||||||
if (!Menu && !Interface->IsOpen())
|
if (!Menu && !Interface->IsOpen())
|
||||||
@ -758,7 +781,8 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!Menu) {
|
if (!Menu) {
|
||||||
EITScanner.Process();
|
if (!TimerInVpsMargin)
|
||||||
|
EITScanner.Process();
|
||||||
if (!cCutter::Active() && cCutter::Ended()) {
|
if (!cCutter::Active() && cCutter::Ended()) {
|
||||||
if (cCutter::Error())
|
if (cCutter::Error())
|
||||||
Interface->Error(tr("Editing process failed!"));
|
Interface->Error(tr("Editing process failed!"));
|
||||||
|
Loading…
Reference in New Issue
Block a user