mirror of
https://github.com/VDR4Arch/vdr.git
synced 2023-10-10 13:36:52 +02:00
Timers now internally have a pointer to their channel
This commit is contained in:
parent
ab4ceb29a0
commit
ac9622bb8a
4
HISTORY
4
HISTORY
@ -1611,7 +1611,7 @@ Video Disk Recorder Revision History
|
|||||||
shall be executed from the "Recordings" menu; see MANUAL and 'man vdr(5)' for
|
shall be executed from the "Recordings" menu; see MANUAL and 'man vdr(5)' for
|
||||||
details (suggested by Gerhard Steiner).
|
details (suggested by Gerhard Steiner).
|
||||||
|
|
||||||
2002-10-19: Version 1.1.14
|
2002-10-20: Version 1.1.14
|
||||||
|
|
||||||
- Fixed some faulty default parameter initializations (thanks to Robert Schiele).
|
- Fixed some faulty default parameter initializations (thanks to Robert Schiele).
|
||||||
- Added further satellites to 'sources.conf' (thanks to Reinhard Walter Buchner).
|
- Added further satellites to 'sources.conf' (thanks to Reinhard Walter Buchner).
|
||||||
@ -1624,3 +1624,5 @@ Video Disk Recorder Revision History
|
|||||||
used to create 'gaps' in the channel numbering (see 'man 5 vdr'). BE CAREFUL
|
used to create 'gaps' in the channel numbering (see 'man 5 vdr'). BE CAREFUL
|
||||||
TO UPDATE YOUR 'timers.conf' ACCORDINGLY IF INSERTING THIS NEW FEATURE INTO YOUR
|
TO UPDATE YOUR 'timers.conf' ACCORDINGLY IF INSERTING THIS NEW FEATURE INTO YOUR
|
||||||
'channels.conf' FILE!
|
'channels.conf' FILE!
|
||||||
|
- Timers now internally have a pointer to their channel (this is necessary to
|
||||||
|
handle gaps in channel numbers, and in preparation for unique channel ids).
|
||||||
|
4
Makefile
4
Makefile
@ -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: Makefile 1.48 2002/10/04 14:29:14 kls Exp $
|
# $Id: Makefile 1.49 2002/10/19 15:46:08 kls Exp $
|
||||||
|
|
||||||
.DELETE_ON_ERROR:
|
.DELETE_ON_ERROR:
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ OBJS = audio.o channels.o config.o cutter.o device.o diseqc.o dvbdevice.o dvbosd
|
|||||||
dvbplayer.o dvbspu.o eit.o eitscan.o font.o i18n.o interface.o keys.o\
|
dvbplayer.o dvbspu.o eit.o eitscan.o font.o i18n.o interface.o keys.o\
|
||||||
lirc.o menu.o menuitems.o osdbase.o osd.o player.o plugin.o rcu.o\
|
lirc.o menu.o menuitems.o osdbase.o osd.o player.o plugin.o rcu.o\
|
||||||
receiver.o recorder.o recording.o remote.o remux.o ringbuffer.o sources.o\
|
receiver.o recorder.o recording.o remote.o remux.o ringbuffer.o sources.o\
|
||||||
spu.o status.o svdrp.o thread.o tools.o transfer.o vdr.o videodir.o
|
spu.o status.o svdrp.o thread.o timers.o tools.o transfer.o vdr.o videodir.o
|
||||||
|
|
||||||
OSDFONT = -adobe-helvetica-medium-r-normal--23-*-100-100-p-*-iso8859-1
|
OSDFONT = -adobe-helvetica-medium-r-normal--23-*-100-100-p-*-iso8859-1
|
||||||
FIXFONT = -adobe-courier-bold-r-normal--25-*-100-100-m-*-iso8859-1
|
FIXFONT = -adobe-courier-bold-r-normal--25-*-100-100-m-*-iso8859-1
|
||||||
|
@ -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: channels.c 1.4 2002/10/19 14:46:05 kls Exp $
|
* $Id: channels.c 1.5 2002/10/20 11:50:47 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "channels.h"
|
#include "channels.h"
|
||||||
@ -450,9 +450,3 @@ bool cChannels::SwitchTo(int Number)
|
|||||||
cChannel *channel = GetByNumber(Number);
|
cChannel *channel = GetByNumber(Number);
|
||||||
return channel && cDevice::PrimaryDevice()->SwitchChannel(channel, true);
|
return channel && cDevice::PrimaryDevice()->SwitchChannel(channel, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *cChannels::GetChannelNameByNumber(int Number)
|
|
||||||
{
|
|
||||||
cChannel *channel = GetByNumber(Number);
|
|
||||||
return channel ? channel->Name() : NULL;
|
|
||||||
}
|
|
||||||
|
@ -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: channels.h 1.2 2002/10/19 11:48:02 kls Exp $
|
* $Id: channels.h 1.3 2002/10/20 11:50:36 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __CHANNELS_H
|
#ifndef __CHANNELS_H
|
||||||
@ -114,7 +114,6 @@ public:
|
|||||||
void ReNumber(void); // Recalculate 'number' based on channel type
|
void ReNumber(void); // Recalculate 'number' based on channel type
|
||||||
cChannel *GetByNumber(int Number, int SkipGap = 0);
|
cChannel *GetByNumber(int Number, int SkipGap = 0);
|
||||||
cChannel *GetByServiceID(unsigned short ServiceId);
|
cChannel *GetByServiceID(unsigned short ServiceId);
|
||||||
const char *GetChannelNameByNumber(int Number);
|
|
||||||
bool SwitchTo(int Number);
|
bool SwitchTo(int Number);
|
||||||
int MaxNumber(void) { return maxNumber; }
|
int MaxNumber(void) { return maxNumber; }
|
||||||
};
|
};
|
||||||
|
377
config.c
377
config.c
@ -4,13 +4,12 @@
|
|||||||
* 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.110 2002/10/19 11:34:01 kls Exp $
|
* $Id: config.c 1.111 2002/10/19 15:49:51 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "channels.h" //XXX timers!
|
|
||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
#include "interface.h"
|
#include "interface.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
@ -20,339 +19,6 @@
|
|||||||
// 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
|
||||||
// value!
|
// value!
|
||||||
|
|
||||||
// -- cTimer -----------------------------------------------------------------
|
|
||||||
|
|
||||||
char *cTimer::buffer = NULL;
|
|
||||||
|
|
||||||
cTimer::cTimer(bool Instant)
|
|
||||||
{
|
|
||||||
startTime = stopTime = 0;
|
|
||||||
recording = pending = false;
|
|
||||||
active = Instant ? taActInst : taInactive;
|
|
||||||
cChannel *ch = Channels.GetByNumber(cDevice::CurrentChannel());
|
|
||||||
channel = ch ? ch->Number() : 0;
|
|
||||||
time_t t = time(NULL);
|
|
||||||
struct tm tm_r;
|
|
||||||
struct tm *now = localtime_r(&t, &tm_r);
|
|
||||||
day = now->tm_mday;
|
|
||||||
start = now->tm_hour * 100 + now->tm_min;
|
|
||||||
stop = now->tm_hour * 60 + now->tm_min + Setup.InstantRecordTime;
|
|
||||||
stop = (stop / 60) * 100 + (stop % 60);
|
|
||||||
if (stop >= 2400)
|
|
||||||
stop -= 2400;
|
|
||||||
//TODO VPS???
|
|
||||||
priority = Setup.DefaultPriority;
|
|
||||||
lifetime = Setup.DefaultLifetime;
|
|
||||||
*file = 0;
|
|
||||||
firstday = 0;
|
|
||||||
summary = NULL;
|
|
||||||
if (Instant && ch)
|
|
||||||
snprintf(file, sizeof(file), "%s%s", Setup.MarkInstantRecord ? "@" : "", *Setup.NameInstantRecord ? Setup.NameInstantRecord : ch->Name());
|
|
||||||
}
|
|
||||||
|
|
||||||
cTimer::cTimer(const cEventInfo *EventInfo)
|
|
||||||
{
|
|
||||||
startTime = stopTime = 0;
|
|
||||||
recording = pending = false;
|
|
||||||
active = true;
|
|
||||||
cChannel *ch = Channels.GetByServiceID(EventInfo->GetServiceID());
|
|
||||||
channel = ch ? ch->Number() : 0;
|
|
||||||
time_t tstart = EventInfo->GetTime();
|
|
||||||
time_t tstop = tstart + EventInfo->GetDuration() + Setup.MarginStop * 60;
|
|
||||||
tstart -= Setup.MarginStart * 60;
|
|
||||||
struct tm tm_r;
|
|
||||||
struct tm *time = localtime_r(&tstart, &tm_r);
|
|
||||||
day = time->tm_mday;
|
|
||||||
start = time->tm_hour * 100 + time->tm_min;
|
|
||||||
time = localtime_r(&tstop, &tm_r);
|
|
||||||
stop = time->tm_hour * 100 + time->tm_min;
|
|
||||||
if (stop >= 2400)
|
|
||||||
stop -= 2400;
|
|
||||||
priority = Setup.DefaultPriority;
|
|
||||||
lifetime = Setup.DefaultLifetime;
|
|
||||||
*file = 0;
|
|
||||||
const char *Title = EventInfo->GetTitle();
|
|
||||||
if (!isempty(Title))
|
|
||||||
strn0cpy(file, EventInfo->GetTitle(), sizeof(file));
|
|
||||||
firstday = 0;
|
|
||||||
summary = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
cTimer::~cTimer()
|
|
||||||
{
|
|
||||||
free(summary);
|
|
||||||
}
|
|
||||||
|
|
||||||
cTimer& cTimer::operator= (const cTimer &Timer)
|
|
||||||
{
|
|
||||||
memcpy(this, &Timer, sizeof(*this));
|
|
||||||
if (summary)
|
|
||||||
summary = strdup(summary);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cTimer::operator< (const cListObject &ListObject)
|
|
||||||
{
|
|
||||||
cTimer *ti = (cTimer *)&ListObject;
|
|
||||||
time_t t1 = StartTime();
|
|
||||||
time_t t2 = ti->StartTime();
|
|
||||||
return t1 < t2 || (t1 == t2 && priority > ti->priority);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *cTimer::ToText(cTimer *Timer)
|
|
||||||
{
|
|
||||||
free(buffer);
|
|
||||||
strreplace(Timer->file, ':', '|');
|
|
||||||
strreplace(Timer->summary, '\n', '|');
|
|
||||||
asprintf(&buffer, "%d:%d:%s:%04d:%04d:%d:%d:%s:%s\n", Timer->active, Timer->channel, PrintDay(Timer->day, Timer->firstday), Timer->start, Timer->stop, Timer->priority, Timer->lifetime, Timer->file, Timer->summary ? Timer->summary : "");
|
|
||||||
strreplace(Timer->summary, '|', '\n');
|
|
||||||
strreplace(Timer->file, '|', ':');
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *cTimer::ToText(void)
|
|
||||||
{
|
|
||||||
return ToText(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
int cTimer::TimeToInt(int t)
|
|
||||||
{
|
|
||||||
return (t / 100 * 60 + t % 100) * 60;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cTimer::ParseDay(const char *s, time_t *FirstDay)
|
|
||||||
{
|
|
||||||
char *tail;
|
|
||||||
int d = strtol(s, &tail, 10);
|
|
||||||
if (FirstDay)
|
|
||||||
*FirstDay = 0;
|
|
||||||
if (tail && *tail) {
|
|
||||||
d = 0;
|
|
||||||
if (tail == s) {
|
|
||||||
const char *first = strchr(s, '@');
|
|
||||||
int l = first ? first - s : strlen(s);
|
|
||||||
if (l == 7) {
|
|
||||||
for (const char *p = s + 6; p >= s; p--) {
|
|
||||||
d <<= 1;
|
|
||||||
d |= (*p != '-');
|
|
||||||
}
|
|
||||||
d |= 0x80000000;
|
|
||||||
}
|
|
||||||
if (FirstDay && first) {
|
|
||||||
++first;
|
|
||||||
if (strlen(first) == 10) {
|
|
||||||
struct tm tm_r;
|
|
||||||
if (3 == sscanf(first, "%d-%d-%d", &tm_r.tm_year, &tm_r.tm_mon, &tm_r.tm_mday)) {
|
|
||||||
tm_r.tm_year -= 1900;
|
|
||||||
tm_r.tm_mon--;
|
|
||||||
tm_r.tm_hour = tm_r.tm_min = tm_r.tm_sec = 0;
|
|
||||||
tm_r.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting
|
|
||||||
*FirstDay = mktime(&tm_r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
d = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (d < 1 || d > 31)
|
|
||||||
d = 0;
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *cTimer::PrintDay(int d, time_t FirstDay)
|
|
||||||
{
|
|
||||||
#define DAYBUFFERSIZE 32
|
|
||||||
static char buffer[DAYBUFFERSIZE];
|
|
||||||
if ((d & 0x80000000) != 0) {
|
|
||||||
char *b = buffer;
|
|
||||||
const char *w = tr("MTWTFSS");
|
|
||||||
while (*w) {
|
|
||||||
*b++ = (d & 1) ? *w : '-';
|
|
||||||
d >>= 1;
|
|
||||||
w++;
|
|
||||||
}
|
|
||||||
if (FirstDay) {
|
|
||||||
struct tm tm_r;
|
|
||||||
localtime_r(&FirstDay, &tm_r);
|
|
||||||
b += strftime(b, DAYBUFFERSIZE - (b - buffer), "@%Y-%m-%d", &tm_r);
|
|
||||||
}
|
|
||||||
*b = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
sprintf(buffer, "%d", d);
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *cTimer::PrintFirstDay(void)
|
|
||||||
{
|
|
||||||
if (firstday) {
|
|
||||||
const char *s = PrintDay(day, firstday);
|
|
||||||
if (strlen(s) == 18)
|
|
||||||
return s + 8;
|
|
||||||
}
|
|
||||||
return ""; // not NULL, so the caller can always use the result
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cTimer::Parse(const char *s)
|
|
||||||
{
|
|
||||||
char *buffer1 = NULL;
|
|
||||||
char *buffer2 = NULL;
|
|
||||||
free(summary);
|
|
||||||
summary = NULL;
|
|
||||||
//XXX Apparently sscanf() doesn't work correctly if the last %a argument
|
|
||||||
//XXX results in an empty string (this first occured when the EIT gathering
|
|
||||||
//XXX was put into a separate thread - don't know why this happens...
|
|
||||||
//XXX As a cure we copy the original string and add a blank.
|
|
||||||
//XXX If anybody can shed some light on why sscanf() failes here, I'd love
|
|
||||||
//XXX to hear about that!
|
|
||||||
char *s2 = NULL;
|
|
||||||
int l2 = strlen(s);
|
|
||||||
while (l2 > 0 && isspace(s[l2 - 1]))
|
|
||||||
l2--;
|
|
||||||
if (s[l2 - 1] == ':') {
|
|
||||||
s2 = MALLOC(char, l2 + 3);
|
|
||||||
strcat(strn0cpy(s2, s, l2 + 1), " \n");
|
|
||||||
s = s2;
|
|
||||||
}
|
|
||||||
if (8 <= sscanf(s, "%d :%d :%a[^:]:%d :%d :%d :%d :%a[^:\n]:%a[^\n]", &active, &channel, &buffer1, &start, &stop, &priority, &lifetime, &buffer2, &summary)) {
|
|
||||||
if (summary && !*skipspace(summary)) {
|
|
||||||
free(summary);
|
|
||||||
summary = NULL;
|
|
||||||
}
|
|
||||||
//TODO add more plausibility checks
|
|
||||||
day = ParseDay(buffer1, &firstday);
|
|
||||||
strn0cpy(file, buffer2, MaxFileName);
|
|
||||||
strreplace(file, '|', ':');
|
|
||||||
strreplace(summary, '|', '\n');
|
|
||||||
free(buffer1);
|
|
||||||
free(buffer2);
|
|
||||||
free(s2);
|
|
||||||
return day != 0;
|
|
||||||
}
|
|
||||||
free(s2);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cTimer::Save(FILE *f)
|
|
||||||
{
|
|
||||||
return fprintf(f, ToText()) > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cTimer::IsSingleEvent(void)
|
|
||||||
{
|
|
||||||
return (day & 0x80000000) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cTimer::GetMDay(time_t t)
|
|
||||||
{
|
|
||||||
struct tm tm_r;
|
|
||||||
return localtime_r(&t, &tm_r)->tm_mday;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cTimer::GetWDay(time_t t)
|
|
||||||
{
|
|
||||||
struct tm tm_r;
|
|
||||||
int weekday = localtime_r(&t, &tm_r)->tm_wday;
|
|
||||||
return weekday == 0 ? 6 : weekday - 1; // we start with monday==0!
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cTimer::DayMatches(time_t t)
|
|
||||||
{
|
|
||||||
return IsSingleEvent() ? GetMDay(t) == day : (day & (1 << GetWDay(t))) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
time_t cTimer::IncDay(time_t t, int Days)
|
|
||||||
{
|
|
||||||
struct tm tm_r;
|
|
||||||
tm tm = *localtime_r(&t, &tm_r);
|
|
||||||
tm.tm_mday += Days; // now tm_mday may be out of its valid range
|
|
||||||
int h = tm.tm_hour; // save original hour to compensate for DST change
|
|
||||||
tm.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting
|
|
||||||
t = mktime(&tm); // normalize all values
|
|
||||||
tm.tm_hour = h; // compensate for DST change
|
|
||||||
return mktime(&tm); // calculate final result
|
|
||||||
}
|
|
||||||
|
|
||||||
time_t cTimer::SetTime(time_t t, int SecondsFromMidnight)
|
|
||||||
{
|
|
||||||
struct tm tm_r;
|
|
||||||
tm tm = *localtime_r(&t, &tm_r);
|
|
||||||
tm.tm_hour = SecondsFromMidnight / 3600;
|
|
||||||
tm.tm_min = (SecondsFromMidnight % 3600) / 60;
|
|
||||||
tm.tm_sec = SecondsFromMidnight % 60;
|
|
||||||
tm.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting
|
|
||||||
return mktime(&tm);
|
|
||||||
}
|
|
||||||
|
|
||||||
char *cTimer::SetFile(const char *File)
|
|
||||||
{
|
|
||||||
if (!isempty(File))
|
|
||||||
strn0cpy(file, File, sizeof(file));
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cTimer::Matches(time_t t)
|
|
||||||
{
|
|
||||||
startTime = stopTime = 0;
|
|
||||||
if (t == 0)
|
|
||||||
t = time(NULL);
|
|
||||||
|
|
||||||
int begin = TimeToInt(start); // seconds from midnight
|
|
||||||
int length = TimeToInt(stop) - begin;
|
|
||||||
if (length < 0)
|
|
||||||
length += SECSINDAY;
|
|
||||||
|
|
||||||
int DaysToCheck = IsSingleEvent() ? 61 : 7; // 61 to handle months with 31/30/31
|
|
||||||
for (int i = -1; i <= DaysToCheck; i++) {
|
|
||||||
time_t t0 = IncDay(t, i);
|
|
||||||
if (DayMatches(t0)) {
|
|
||||||
time_t a = SetTime(t0, begin);
|
|
||||||
time_t b = a + length;
|
|
||||||
if ((!firstday || a >= firstday) && t <= b) {
|
|
||||||
startTime = a;
|
|
||||||
stopTime = b;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!startTime)
|
|
||||||
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
|
|
||||||
firstday = 0;
|
|
||||||
return active && startTime <= t && t < stopTime; // must stop *before* stopTime to allow adjacent timers
|
|
||||||
}
|
|
||||||
|
|
||||||
time_t cTimer::StartTime(void)
|
|
||||||
{
|
|
||||||
if (!startTime)
|
|
||||||
Matches();
|
|
||||||
return startTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
time_t cTimer::StopTime(void)
|
|
||||||
{
|
|
||||||
if (!stopTime)
|
|
||||||
Matches();
|
|
||||||
return stopTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cTimer::SetRecording(bool Recording)
|
|
||||||
{
|
|
||||||
recording = Recording;
|
|
||||||
isyslog("timer %d %s", Index() + 1, recording ? "start" : "stop");
|
|
||||||
}
|
|
||||||
|
|
||||||
void cTimer::SetPending(bool Pending)
|
|
||||||
{
|
|
||||||
pending = Pending;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cTimer::Skip(void)
|
|
||||||
{
|
|
||||||
firstday = IncDay(SetTime(StartTime(), 0), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- cCommand -------------------------------------------------------------
|
// --- cCommand -------------------------------------------------------------
|
||||||
|
|
||||||
char *cCommand::result = NULL;
|
char *cCommand::result = NULL;
|
||||||
@ -476,47 +142,6 @@ bool cCaDefinition::Parse(const char *s)
|
|||||||
cCommands Commands;
|
cCommands Commands;
|
||||||
cCommands RecordingCommands;
|
cCommands RecordingCommands;
|
||||||
|
|
||||||
// -- cTimers ----------------------------------------------------------------
|
|
||||||
|
|
||||||
cTimers Timers;
|
|
||||||
|
|
||||||
cTimer *cTimers::GetTimer(cTimer *Timer)
|
|
||||||
{
|
|
||||||
cTimer *ti = (cTimer *)First();
|
|
||||||
while (ti) {
|
|
||||||
if (ti->channel == Timer->channel && ti->day == Timer->day && ti->start == Timer->start && ti->stop == Timer->stop)
|
|
||||||
return ti;
|
|
||||||
ti = (cTimer *)ti->Next();
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
cTimer *cTimers::GetMatch(time_t t)
|
|
||||||
{
|
|
||||||
cTimer *t0 = NULL;
|
|
||||||
cTimer *ti = First();
|
|
||||||
while (ti) {
|
|
||||||
if (!ti->recording && ti->Matches(t)) {
|
|
||||||
if (!t0 || ti->priority > t0->priority)
|
|
||||||
t0 = ti;
|
|
||||||
}
|
|
||||||
ti = (cTimer *)ti->Next();
|
|
||||||
}
|
|
||||||
return t0;
|
|
||||||
}
|
|
||||||
|
|
||||||
cTimer *cTimers::GetNextActiveTimer(void)
|
|
||||||
{
|
|
||||||
cTimer *t0 = NULL;
|
|
||||||
cTimer *ti = First();
|
|
||||||
while (ti) {
|
|
||||||
if (ti->active && (!t0 || *ti < *t0))
|
|
||||||
t0 = ti;
|
|
||||||
ti = (cTimer *)ti->Next();
|
|
||||||
}
|
|
||||||
return t0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- cSVDRPhosts ------------------------------------------------------------
|
// -- cSVDRPhosts ------------------------------------------------------------
|
||||||
|
|
||||||
cSVDRPhosts SVDRPhosts;
|
cSVDRPhosts SVDRPhosts;
|
||||||
|
61
config.h
61
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.136 2002/10/19 11:29:46 kls Exp $
|
* $Id: config.h 1.137 2002/10/19 15:43:31 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __CONFIG_H
|
#ifndef __CONFIG_H
|
||||||
@ -32,57 +32,6 @@
|
|||||||
|
|
||||||
#define MaxFileName 256
|
#define MaxFileName 256
|
||||||
|
|
||||||
enum eTimerActive { taInactive = 0,
|
|
||||||
taActive = 1,
|
|
||||||
taInstant = 2,
|
|
||||||
taActInst = (taActive | taInstant)
|
|
||||||
};
|
|
||||||
|
|
||||||
class cTimer : public cListObject {
|
|
||||||
private:
|
|
||||||
time_t startTime, stopTime;
|
|
||||||
static char *buffer;
|
|
||||||
static const char *ToText(cTimer *Timer);
|
|
||||||
public:
|
|
||||||
bool recording, pending;
|
|
||||||
int active;
|
|
||||||
int channel;
|
|
||||||
int day;
|
|
||||||
int start;
|
|
||||||
int stop;
|
|
||||||
//TODO VPS???
|
|
||||||
int priority;
|
|
||||||
int lifetime;
|
|
||||||
char file[MaxFileName];
|
|
||||||
time_t firstday;
|
|
||||||
char *summary;
|
|
||||||
cTimer(bool Instant = false);
|
|
||||||
cTimer(const cEventInfo *EventInfo);
|
|
||||||
virtual ~cTimer();
|
|
||||||
cTimer& operator= (const cTimer &Timer);
|
|
||||||
virtual bool operator< (const cListObject &ListObject);
|
|
||||||
const char *ToText(void);
|
|
||||||
bool Parse(const char *s);
|
|
||||||
bool Save(FILE *f);
|
|
||||||
bool IsSingleEvent(void);
|
|
||||||
int GetMDay(time_t t);
|
|
||||||
int GetWDay(time_t t);
|
|
||||||
bool DayMatches(time_t t);
|
|
||||||
static time_t IncDay(time_t t, int Days);
|
|
||||||
static time_t SetTime(time_t t, int SecondsFromMidnight);
|
|
||||||
char *SetFile(const char *File);
|
|
||||||
bool Matches(time_t t = 0);
|
|
||||||
time_t StartTime(void);
|
|
||||||
time_t StopTime(void);
|
|
||||||
void SetRecording(bool Recording);
|
|
||||||
void SetPending(bool Pending);
|
|
||||||
void Skip(void);
|
|
||||||
const char *PrintFirstDay(void);
|
|
||||||
static int TimeToInt(int t);
|
|
||||||
static int ParseDay(const char *s, time_t *FirstDay = NULL);
|
|
||||||
static const char *PrintDay(int d, time_t FirstDay = 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
class cCommand : public cListObject {
|
class cCommand : public cListObject {
|
||||||
private:
|
private:
|
||||||
char *title;
|
char *title;
|
||||||
@ -203,13 +152,6 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class cTimers : public cConfig<cTimer> {
|
|
||||||
public:
|
|
||||||
cTimer *GetTimer(cTimer *Timer);
|
|
||||||
cTimer *GetMatch(time_t t);
|
|
||||||
cTimer *GetNextActiveTimer(void);
|
|
||||||
};
|
|
||||||
|
|
||||||
class cCommands : public cConfig<cCommand> {};
|
class cCommands : public cConfig<cCommand> {};
|
||||||
|
|
||||||
class cSVDRPhosts : public cConfig<cSVDRPhost> {
|
class cSVDRPhosts : public cConfig<cSVDRPhost> {
|
||||||
@ -222,7 +164,6 @@ public:
|
|||||||
const cCaDefinition *Get(int Number);
|
const cCaDefinition *Get(int Number);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern cTimers Timers;
|
|
||||||
extern cCommands Commands;
|
extern cCommands Commands;
|
||||||
extern cCommands RecordingCommands;
|
extern cCommands RecordingCommands;
|
||||||
extern cSVDRPhosts SVDRPhosts;
|
extern cSVDRPhosts SVDRPhosts;
|
||||||
|
172
menu.c
172
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.218 2002/10/19 15:33:37 kls Exp $
|
* $Id: menu.c 1.219 2002/10/20 12:03:13 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "menu.h"
|
#include "menu.h"
|
||||||
@ -24,6 +24,7 @@
|
|||||||
#include "remote.h"
|
#include "remote.h"
|
||||||
#include "sources.h"
|
#include "sources.h"
|
||||||
#include "status.h"
|
#include "status.h"
|
||||||
|
#include "timers.h"
|
||||||
#include "videodir.h"
|
#include "videodir.h"
|
||||||
|
|
||||||
#define MENUTIMEOUT 120 // seconds
|
#define MENUTIMEOUT 120 // seconds
|
||||||
@ -617,17 +618,14 @@ eOSState cMenuEditChannel::ProcessKey(eKeys Key)
|
|||||||
|
|
||||||
class cMenuChannelItem : public cOsdItem {
|
class cMenuChannelItem : public cOsdItem {
|
||||||
private:
|
private:
|
||||||
int index;
|
|
||||||
cChannel *channel;
|
cChannel *channel;
|
||||||
public:
|
public:
|
||||||
cMenuChannelItem(int Index, cChannel *Channel);
|
cMenuChannelItem(cChannel *Channel);
|
||||||
virtual void Set(void);
|
virtual void Set(void);
|
||||||
void SetIndex(int Index);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
cMenuChannelItem::cMenuChannelItem(int Index, cChannel *Channel)
|
cMenuChannelItem::cMenuChannelItem(cChannel *Channel)
|
||||||
{
|
{
|
||||||
index = Index;
|
|
||||||
channel = Channel;
|
channel = Channel;
|
||||||
if (channel->GroupSep())
|
if (channel->GroupSep())
|
||||||
SetColor(clrCyan, clrBackground);
|
SetColor(clrCyan, clrBackground);
|
||||||
@ -644,15 +642,11 @@ void cMenuChannelItem::Set(void)
|
|||||||
SetText(buffer, false);
|
SetText(buffer, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cMenuChannelItem::SetIndex(int Index)
|
|
||||||
{
|
|
||||||
index = Index;
|
|
||||||
Set();
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- cMenuChannels ---------------------------------------------------------
|
// --- cMenuChannels ---------------------------------------------------------
|
||||||
|
|
||||||
class cMenuChannels : public cOsdMenu {
|
class cMenuChannels : public cOsdMenu {
|
||||||
|
private:
|
||||||
|
void Propagate(void);
|
||||||
protected:
|
protected:
|
||||||
eOSState Switch(void);
|
eOSState Switch(void);
|
||||||
eOSState Edit(void);
|
eOSState Edit(void);
|
||||||
@ -673,12 +667,22 @@ cMenuChannels::cMenuChannels(void)
|
|||||||
int curr = ((channel = Channels.GetByNumber(cDevice::CurrentChannel())) != NULL) ? channel->Index() : -1;
|
int curr = ((channel = Channels.GetByNumber(cDevice::CurrentChannel())) != NULL) ? channel->Index() : -1;
|
||||||
|
|
||||||
while ((channel = Channels.Get(i)) != NULL) {
|
while ((channel = Channels.Get(i)) != NULL) {
|
||||||
Add(new cMenuChannelItem(i, channel), i == curr);
|
Add(new cMenuChannelItem(channel), i == curr);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
SetHelp(tr("Edit"), tr("New"), tr("Delete"), tr("Mark"));
|
SetHelp(tr("Edit"), tr("New"), tr("Delete"), tr("Mark"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cMenuChannels::Propagate(void)
|
||||||
|
{
|
||||||
|
Channels.ReNumber();
|
||||||
|
Channels.Save();
|
||||||
|
for (cMenuChannelItem *ci = (cMenuChannelItem *)First(); ci; ci = (cMenuChannelItem *)ci->Next())
|
||||||
|
ci->Set();
|
||||||
|
Timers.Save(); // channel numbering has changed!
|
||||||
|
Display();
|
||||||
|
}
|
||||||
|
|
||||||
eOSState cMenuChannels::Switch(void)
|
eOSState cMenuChannels::Switch(void)
|
||||||
{
|
{
|
||||||
cChannel *ch = Channels.Get(Current());
|
cChannel *ch = Channels.Get(Current());
|
||||||
@ -702,7 +706,7 @@ eOSState cMenuChannels::New(void)
|
|||||||
cChannel *channel = new cChannel(Channels.Get(Current()));
|
cChannel *channel = new cChannel(Channels.Get(Current()));
|
||||||
Channels.Add(channel);
|
Channels.Add(channel);
|
||||||
Channels.ReNumber();
|
Channels.ReNumber();
|
||||||
Add(new cMenuChannelItem(channel->Index()/*XXX*/, channel), true);
|
Add(new cMenuChannelItem(channel), true);
|
||||||
Channels.Save();
|
Channels.Save();
|
||||||
isyslog("channel %d added", channel->Number());
|
isyslog("channel %d added", channel->Number());
|
||||||
return AddSubMenu(new cMenuEditChannel(Current()));
|
return AddSubMenu(new cMenuEditChannel(Current()));
|
||||||
@ -715,36 +719,17 @@ eOSState cMenuChannels::Del(void)
|
|||||||
cChannel *channel = Channels.Get(Index);
|
cChannel *channel = Channels.Get(Index);
|
||||||
int DeletedChannel = channel->Number();
|
int DeletedChannel = channel->Number();
|
||||||
// Check if there is a timer using this channel:
|
// Check if there is a timer using this channel:
|
||||||
for (cTimer *ti = Timers.First(); ti; ti = (cTimer *)ti->Next()) {
|
for (cTimer *ti = Timers.First(); ti; ti = Timers.Next(ti)) {
|
||||||
if (ti->channel == DeletedChannel) {
|
if (ti->Channel() == channel) {
|
||||||
Interface->Error(tr("Channel is being used by a timer!"));
|
Interface->Error(tr("Channel is being used by a timer!"));
|
||||||
return osContinue;
|
return osContinue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Interface->Confirm(tr("Delete channel?"))) {
|
if (Interface->Confirm(tr("Delete channel?"))) {
|
||||||
// Move and renumber the channels:
|
|
||||||
Channels.Del(channel);
|
Channels.Del(channel);
|
||||||
Channels.ReNumber();
|
|
||||||
cOsdMenu::Del(Index);
|
cOsdMenu::Del(Index);
|
||||||
int i = 0;
|
Propagate();
|
||||||
for (cMenuChannelItem *ci = (cMenuChannelItem *)First(); ci; ci = (cMenuChannelItem *)ci->Next())
|
|
||||||
ci->SetIndex(i++);
|
|
||||||
Channels.Save();
|
|
||||||
isyslog("channel %d deleted", DeletedChannel);
|
isyslog("channel %d deleted", DeletedChannel);
|
||||||
// Fix the timers:
|
|
||||||
bool TimersModified = false;
|
|
||||||
for (cTimer *ti = Timers.First(); ti; ti = (cTimer *)ti->Next()) {
|
|
||||||
int OldChannel = ti->channel;
|
|
||||||
if (ti->channel > DeletedChannel)
|
|
||||||
ti->channel--;
|
|
||||||
if (ti->channel != OldChannel) {
|
|
||||||
TimersModified = true;
|
|
||||||
isyslog("timer %d: channel changed from %d to %d", ti->Index() + 1, OldChannel, ti->channel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (TimersModified)
|
|
||||||
Timers.Save();
|
|
||||||
Display();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return osContinue;
|
return osContinue;
|
||||||
@ -754,35 +739,10 @@ void cMenuChannels::Move(int From, int To)
|
|||||||
{
|
{
|
||||||
int FromNumber = Channels.Get(From)->Number();
|
int FromNumber = Channels.Get(From)->Number();
|
||||||
int ToNumber = Channels.Get(To)->Number();
|
int ToNumber = Channels.Get(To)->Number();
|
||||||
// Move and renumber the channels:
|
|
||||||
Channels.Move(From, To);
|
Channels.Move(From, To);
|
||||||
Channels.ReNumber();
|
|
||||||
cOsdMenu::Move(From, To);
|
cOsdMenu::Move(From, To);
|
||||||
int i = 0;
|
Propagate();
|
||||||
for (cMenuChannelItem *ci = (cMenuChannelItem *)First(); ci; ci = (cMenuChannelItem *)ci->Next())
|
|
||||||
ci->SetIndex(i++);
|
|
||||||
Channels.Save();
|
|
||||||
isyslog("channel %d moved to %d", FromNumber, ToNumber);
|
isyslog("channel %d moved to %d", FromNumber, ToNumber);
|
||||||
// Fix the timers:
|
|
||||||
bool TimersModified = false;
|
|
||||||
From++; // user visible channel numbers start with '1'
|
|
||||||
To++;
|
|
||||||
for (cTimer *ti = Timers.First(); ti; ti = (cTimer *)ti->Next()) {
|
|
||||||
int OldChannel = ti->channel;
|
|
||||||
if (ti->channel == FromNumber)
|
|
||||||
ti->channel = ToNumber;
|
|
||||||
else if (ti->channel > FromNumber && ti->channel <= ToNumber)
|
|
||||||
ti->channel--;
|
|
||||||
else if (ti->channel < FromNumber && ti->channel >= ToNumber)
|
|
||||||
ti->channel++;
|
|
||||||
if (ti->channel != OldChannel) {
|
|
||||||
TimersModified = true;
|
|
||||||
isyslog("timer %d: channel changed from %d to %d", ti->Index() + 1, OldChannel, ti->channel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (TimersModified)
|
|
||||||
Timers.Save();
|
|
||||||
Display();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
eOSState cMenuChannels::ProcessKey(eKeys Key)
|
eOSState cMenuChannels::ProcessKey(eKeys Key)
|
||||||
@ -835,6 +795,7 @@ class cMenuEditTimer : public cOsdMenu {
|
|||||||
private:
|
private:
|
||||||
cTimer *timer;
|
cTimer *timer;
|
||||||
cTimer data;
|
cTimer data;
|
||||||
|
int channel;
|
||||||
cMenuEditDateItem *firstday;
|
cMenuEditDateItem *firstday;
|
||||||
void SetFirstDayItem(void);
|
void SetFirstDayItem(void);
|
||||||
public:
|
public:
|
||||||
@ -851,12 +812,12 @@ cMenuEditTimer::cMenuEditTimer(int Index, bool New)
|
|||||||
data = *timer;
|
data = *timer;
|
||||||
if (New)
|
if (New)
|
||||||
data.active = 1;
|
data.active = 1;
|
||||||
|
channel = data.Channel()->Number();
|
||||||
Add(new cMenuEditBoolItem(tr("Active"), &data.active));
|
Add(new cMenuEditBoolItem(tr("Active"), &data.active));
|
||||||
Add(new cMenuEditChanItem(tr("Channel"), &data.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));
|
||||||
//TODO VPS???
|
|
||||||
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)));
|
||||||
@ -884,15 +845,24 @@ eOSState cMenuEditTimer::ProcessKey(eKeys Key)
|
|||||||
|
|
||||||
if (state == osUnknown) {
|
if (state == osUnknown) {
|
||||||
switch (Key) {
|
switch (Key) {
|
||||||
case kOk: if (!*data.file)
|
case kOk: {
|
||||||
strcpy(data.file, Channels.GetChannelNameByNumber(data.channel));
|
cChannel *ch = Channels.GetByNumber(channel);
|
||||||
if (timer && memcmp(timer, &data, sizeof(data)) != 0) {
|
if (ch)
|
||||||
*timer = data;
|
data.channel = ch;
|
||||||
if (timer->active)
|
else {
|
||||||
timer->active = 1; // allows external programs to mark active timers with values > 1 and recognize if the user has modified them
|
Interface->Error(tr("*** Invalid Channel ***"));
|
||||||
Timers.Save();
|
break;
|
||||||
isyslog("timer %d modified (%s)", timer->Index() + 1, timer->active ? "active" : "inactive");
|
}
|
||||||
}
|
if (!*data.file)
|
||||||
|
strcpy(data.file, data.Channel()->Name());
|
||||||
|
if (timer && memcmp(timer, &data, sizeof(data)) != 0) {
|
||||||
|
*timer = data;
|
||||||
|
if (timer->active)
|
||||||
|
timer->active = 1; // allows external programs to mark active timers with values > 1 and recognize if the user has modified them
|
||||||
|
Timers.Save();
|
||||||
|
isyslog("timer %d modified (%s)", timer->Index() + 1, timer->active ? "active" : "inactive");
|
||||||
|
}
|
||||||
|
}
|
||||||
return osBack;
|
return osBack;
|
||||||
case kRed:
|
case kRed:
|
||||||
case kGreen:
|
case kGreen:
|
||||||
@ -933,14 +903,14 @@ 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->Active() ? ' ' : timer->FirstDay() ? '!' : timer->Recording() ? '#' : '>',
|
||||||
timer->channel,
|
timer->Channel()->Number(),
|
||||||
timer->PrintDay(timer->day),
|
timer->PrintDay(timer->Day()),
|
||||||
timer->start / 100,
|
timer->Start() / 100,
|
||||||
timer->start % 100,
|
timer->Start() % 100,
|
||||||
timer->stop / 100,
|
timer->Stop() / 100,
|
||||||
timer->stop % 100,
|
timer->Stop() % 100,
|
||||||
timer->file);
|
timer->File());
|
||||||
SetText(buffer, false);
|
SetText(buffer, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -985,23 +955,13 @@ eOSState cMenuTimers::OnOff(void)
|
|||||||
{
|
{
|
||||||
cTimer *timer = CurrentTimer();
|
cTimer *timer = CurrentTimer();
|
||||||
if (timer) {
|
if (timer) {
|
||||||
if (timer->IsSingleEvent())
|
timer->OnOff();
|
||||||
timer->active = !timer->active;
|
|
||||||
else if (timer->firstday) {
|
|
||||||
timer->firstday = 0;
|
|
||||||
timer->active = false;
|
|
||||||
}
|
|
||||||
else if (timer->active)
|
|
||||||
timer->Skip();
|
|
||||||
else
|
|
||||||
timer->active = true;
|
|
||||||
timer->Matches(); // refresh start and end time
|
|
||||||
RefreshCurrent();
|
RefreshCurrent();
|
||||||
DisplayCurrent(true);
|
DisplayCurrent(true);
|
||||||
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->Active() ? "" : "de");
|
||||||
Timers.Save();
|
Timers.Save();
|
||||||
}
|
}
|
||||||
return osContinue;
|
return osContinue;
|
||||||
@ -1032,7 +992,7 @@ eOSState cMenuTimers::Del(void)
|
|||||||
// Check if this timer is active:
|
// Check if this timer is active:
|
||||||
cTimer *ti = CurrentTimer();
|
cTimer *ti = CurrentTimer();
|
||||||
if (ti) {
|
if (ti) {
|
||||||
if (!ti->recording) {
|
if (!ti->Recording()) {
|
||||||
if (Interface->Confirm(tr("Delete timer?"))) {
|
if (Interface->Confirm(tr("Delete timer?"))) {
|
||||||
int Index = ti->Index();
|
int Index = ti->Index();
|
||||||
Timers.Del(ti);
|
Timers.Del(ti);
|
||||||
@ -1062,8 +1022,8 @@ eOSState cMenuTimers::Summary(void)
|
|||||||
if (HasSubMenu() || Count() == 0)
|
if (HasSubMenu() || Count() == 0)
|
||||||
return osContinue;
|
return osContinue;
|
||||||
cTimer *ti = CurrentTimer();
|
cTimer *ti = CurrentTimer();
|
||||||
if (ti && ti->summary && *ti->summary)
|
if (ti && !isempty(ti->Summary()))
|
||||||
return AddSubMenu(new cMenuText(tr("Summary"), ti->summary));
|
return AddSubMenu(new cMenuText(tr("Summary"), ti->Summary()));
|
||||||
return Edit(); // convenience for people not using the Summary feature ;-)
|
return Edit(); // convenience for people not using the Summary feature ;-)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2675,7 +2635,7 @@ cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer)
|
|||||||
timer = new cTimer(true);
|
timer = new cTimer(true);
|
||||||
Timers.Add(timer);
|
Timers.Add(timer);
|
||||||
Timers.Save();
|
Timers.Save();
|
||||||
asprintf(&instantId, cDevice::NumDevices() > 1 ? "%s - %d" : "%s", Channels.GetChannelNameByNumber(timer->channel), device->CardIndex() + 1);
|
asprintf(&instantId, cDevice::NumDevices() > 1 ? "%s - %d" : "%s", timer->Channel()->Name(), device->CardIndex() + 1);
|
||||||
}
|
}
|
||||||
timer->SetPending(true);
|
timer->SetPending(true);
|
||||||
timer->SetRecording(true);
|
timer->SetRecording(true);
|
||||||
@ -2692,8 +2652,8 @@ cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer)
|
|||||||
cRecording Recording(timer, Title, Subtitle, Summary);
|
cRecording Recording(timer, Title, Subtitle, Summary);
|
||||||
fileName = strdup(Recording.FileName());
|
fileName = strdup(Recording.FileName());
|
||||||
cRecordingUserCommand::InvokeCommand(RUC_BEFORERECORDING, fileName);
|
cRecordingUserCommand::InvokeCommand(RUC_BEFORERECORDING, fileName);
|
||||||
cChannel *ch = Channels.GetByNumber(timer->channel);
|
const cChannel *ch = timer->Channel();
|
||||||
recorder = new cRecorder(fileName, ch->Ca(), timer->priority, ch->Vpid(), ch->Apid1(), ch->Apid2(), ch->Dpid1(), ch->Dpid2());
|
recorder = new cRecorder(fileName, ch->Ca(), timer->Priority(), ch->Vpid(), ch->Apid1(), ch->Apid2(), ch->Dpid1(), ch->Dpid2());
|
||||||
if (device->AttachReceiver(recorder)) {
|
if (device->AttachReceiver(recorder)) {
|
||||||
Recording.WriteSummary();
|
Recording.WriteSummary();
|
||||||
cStatus::MsgRecording(device, Recording.Name());
|
cStatus::MsgRecording(device, Recording.Name());
|
||||||
@ -2713,8 +2673,8 @@ cRecordControl::~cRecordControl()
|
|||||||
|
|
||||||
bool cRecordControl::GetEventInfo(void)
|
bool cRecordControl::GetEventInfo(void)
|
||||||
{
|
{
|
||||||
cChannel *channel = Channels.GetByNumber(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->Active() == taActInst ? 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++) {
|
||||||
{
|
{
|
||||||
cMutexLock MutexLock;
|
cMutexLock MutexLock;
|
||||||
@ -2759,7 +2719,7 @@ bool cRecordControl::Process(time_t t)
|
|||||||
{
|
{
|
||||||
if (!recorder || !timer || !timer->Matches(t))
|
if (!recorder || !timer || !timer->Matches(t))
|
||||||
return false;
|
return false;
|
||||||
AssertFreeDiskSpace(timer->priority);
|
AssertFreeDiskSpace(timer->Priority());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2769,12 +2729,12 @@ cRecordControl *cRecordControls::RecordControls[MAXRECORDCONTROLS] = { NULL };
|
|||||||
|
|
||||||
bool cRecordControls::Start(cTimer *Timer)
|
bool cRecordControls::Start(cTimer *Timer)
|
||||||
{
|
{
|
||||||
int ch = Timer ? Timer->channel : cDevice::CurrentChannel();
|
int ch = Timer ? Timer->Channel()->Number() : cDevice::CurrentChannel();
|
||||||
cChannel *channel = Channels.GetByNumber(ch);
|
cChannel *channel = Channels.GetByNumber(ch);
|
||||||
|
|
||||||
if (channel) {
|
if (channel) {
|
||||||
bool NeedsDetachReceivers = false;
|
bool NeedsDetachReceivers = false;
|
||||||
cDevice *device = cDevice::GetDevice(channel, Timer ? Timer->priority : Setup.DefaultPriority, &NeedsDetachReceivers);
|
cDevice *device = cDevice::GetDevice(channel, Timer ? Timer->Priority() : Setup.DefaultPriority, &NeedsDetachReceivers);
|
||||||
if (device) {
|
if (device) {
|
||||||
if (NeedsDetachReceivers)
|
if (NeedsDetachReceivers)
|
||||||
Stop(device);
|
Stop(device);
|
||||||
@ -2789,7 +2749,7 @@ bool cRecordControls::Start(cTimer *Timer)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
20
recording.c
20
recording.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: recording.c 1.69 2002/10/13 09:08:45 kls Exp $
|
* $Id: recording.c 1.70 2002/10/20 11:54:29 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "recording.h"
|
#include "recording.h"
|
||||||
@ -307,13 +307,13 @@ cRecording::cRecording(cTimer *Timer, const char *Title, const char *Subtitle, c
|
|||||||
name = NULL;
|
name = NULL;
|
||||||
// set up the actual name:
|
// set up the actual name:
|
||||||
if (isempty(Title))
|
if (isempty(Title))
|
||||||
Title = Channels.GetChannelNameByNumber(Timer->channel);
|
Title = Timer->Channel()->Name();
|
||||||
if (isempty(Subtitle))
|
if (isempty(Subtitle))
|
||||||
Subtitle = " ";
|
Subtitle = " ";
|
||||||
char *macroTITLE = strstr(Timer->file, TIMERMACRO_TITLE);
|
char *macroTITLE = strstr(Timer->File(), TIMERMACRO_TITLE);
|
||||||
char *macroEPISODE = strstr(Timer->file, TIMERMACRO_EPISODE);
|
char *macroEPISODE = strstr(Timer->File(), TIMERMACRO_EPISODE);
|
||||||
if (macroTITLE || macroEPISODE) {
|
if (macroTITLE || macroEPISODE) {
|
||||||
name = strdup(Timer->file);
|
name = strdup(Timer->File());
|
||||||
name = strreplace(name, TIMERMACRO_TITLE, Title);
|
name = strreplace(name, TIMERMACRO_TITLE, Title);
|
||||||
name = strreplace(name, TIMERMACRO_EPISODE, Subtitle);
|
name = strreplace(name, TIMERMACRO_EPISODE, Subtitle);
|
||||||
if (Timer->IsSingleEvent()) {
|
if (Timer->IsSingleEvent()) {
|
||||||
@ -322,16 +322,16 @@ cRecording::cRecording(cTimer *Timer, const char *Title, const char *Subtitle, c
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Timer->IsSingleEvent() || !Setup.UseSubtitle)
|
else if (Timer->IsSingleEvent() || !Setup.UseSubtitle)
|
||||||
name = strdup(Timer->file);
|
name = strdup(Timer->File());
|
||||||
else
|
else
|
||||||
asprintf(&name, "%s~%s", Timer->file, Subtitle);
|
asprintf(&name, "%s~%s", Timer->File(), Subtitle);
|
||||||
// substitute characters that would cause problems in file names:
|
// substitute characters that would cause problems in file names:
|
||||||
strreplace(name, '\n', ' ');
|
strreplace(name, '\n', ' ');
|
||||||
start = Timer->StartTime();
|
start = Timer->StartTime();
|
||||||
priority = Timer->priority;
|
priority = Timer->Priority();
|
||||||
lifetime = Timer->lifetime;
|
lifetime = Timer->Lifetime();
|
||||||
// handle summary:
|
// handle summary:
|
||||||
summary = !isempty(Timer->summary) ? strdup(Timer->summary) : NULL;
|
summary = !isempty(Timer->Summary()) ? strdup(Timer->Summary()) : NULL;
|
||||||
if (!summary) {
|
if (!summary) {
|
||||||
if (isempty(Subtitle))
|
if (isempty(Subtitle))
|
||||||
Subtitle = "";
|
Subtitle = "";
|
||||||
|
@ -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: recording.h 1.24 2002/06/22 10:09:27 kls Exp $
|
* $Id: recording.h 1.25 2002/10/19 15:48:52 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __RECORDING_H
|
#ifndef __RECORDING_H
|
||||||
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "timers.h"
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
|
|
||||||
void RemoveDeletedRecordings(void);
|
void RemoveDeletedRecordings(void);
|
||||||
|
11
svdrp.c
11
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.46 2002/10/19 11:48:02 kls Exp $
|
* $Id: svdrp.c 1.47 2002/10/20 10:24:20 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "svdrp.h"
|
#include "svdrp.h"
|
||||||
@ -31,6 +31,7 @@
|
|||||||
#include "device.h"
|
#include "device.h"
|
||||||
#include "keys.h"
|
#include "keys.h"
|
||||||
#include "remote.h"
|
#include "remote.h"
|
||||||
|
#include "timers.h"
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
|
|
||||||
// --- cSocket ---------------------------------------------------------------
|
// --- cSocket ---------------------------------------------------------------
|
||||||
@ -487,7 +488,7 @@ void cSVDRP::CmdDELT(const char *Option)
|
|||||||
if (isnumber(Option)) {
|
if (isnumber(Option)) {
|
||||||
cTimer *timer = Timers.Get(strtol(Option, NULL, 10) - 1);
|
cTimer *timer = Timers.Get(strtol(Option, NULL, 10) - 1);
|
||||||
if (timer) {
|
if (timer) {
|
||||||
if (!timer->recording) {
|
if (!timer->Recording()) {
|
||||||
Timers.Del(timer);
|
Timers.Del(timer);
|
||||||
Timers.Save();
|
Timers.Save();
|
||||||
isyslog("timer %s deleted", Option);
|
isyslog("timer %s deleted", Option);
|
||||||
@ -806,16 +807,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.active = 1;
|
t.SetActive(taActive);
|
||||||
else if (strcasecmp(tail, "OFF") == 0)
|
else if (strcasecmp(tail, "OFF") == 0)
|
||||||
t.active = 0;
|
t.SetActive(taInactive);
|
||||||
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->Active() ? "active" : "inactive");
|
||||||
Reply(250, "%d %s", timer->Index() + 1, timer->ToText());
|
Reply(250, "%d %s", timer->Index() + 1, timer->ToText());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
408
timers.c
Normal file
408
timers.c
Normal file
@ -0,0 +1,408 @@
|
|||||||
|
/*
|
||||||
|
* timers.c: Timer handling
|
||||||
|
*
|
||||||
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
|
* how to reach the author.
|
||||||
|
*
|
||||||
|
* $Id: timers.c 1.1 2002/10/20 12:28:55 kls Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "timers.h"
|
||||||
|
#include <ctype.h>
|
||||||
|
#include "channels.h"
|
||||||
|
#include "i18n.h"
|
||||||
|
|
||||||
|
// IMPORTANT NOTE: in the 'sscanf()' calls there is a blank after the '%d'
|
||||||
|
// format characters in order to allow any number of blanks after a numeric
|
||||||
|
// value!
|
||||||
|
|
||||||
|
// -- cTimer -----------------------------------------------------------------
|
||||||
|
|
||||||
|
char *cTimer::buffer = NULL;
|
||||||
|
|
||||||
|
cTimer::cTimer(bool Instant)
|
||||||
|
{
|
||||||
|
startTime = stopTime = 0;
|
||||||
|
recording = pending = false;
|
||||||
|
active = Instant ? taActInst : taInactive;
|
||||||
|
channel = Channels.GetByNumber(cDevice::CurrentChannel());
|
||||||
|
time_t t = time(NULL);
|
||||||
|
struct tm tm_r;
|
||||||
|
struct tm *now = localtime_r(&t, &tm_r);
|
||||||
|
day = now->tm_mday;
|
||||||
|
start = now->tm_hour * 100 + now->tm_min;
|
||||||
|
stop = now->tm_hour * 60 + now->tm_min + Setup.InstantRecordTime;
|
||||||
|
stop = (stop / 60) * 100 + (stop % 60);
|
||||||
|
if (stop >= 2400)
|
||||||
|
stop -= 2400;
|
||||||
|
priority = Setup.DefaultPriority;
|
||||||
|
lifetime = Setup.DefaultLifetime;
|
||||||
|
*file = 0;
|
||||||
|
firstday = 0;
|
||||||
|
summary = NULL;
|
||||||
|
if (Instant && channel)
|
||||||
|
snprintf(file, sizeof(file), "%s%s", Setup.MarkInstantRecord ? "@" : "", *Setup.NameInstantRecord ? Setup.NameInstantRecord : channel->Name());
|
||||||
|
}
|
||||||
|
|
||||||
|
cTimer::cTimer(const cEventInfo *EventInfo)
|
||||||
|
{
|
||||||
|
startTime = stopTime = 0;
|
||||||
|
recording = pending = false;
|
||||||
|
active = true;
|
||||||
|
channel = Channels.GetByServiceID(EventInfo->GetServiceID());
|
||||||
|
time_t tstart = EventInfo->GetTime();
|
||||||
|
time_t tstop = tstart + EventInfo->GetDuration() + Setup.MarginStop * 60;
|
||||||
|
tstart -= Setup.MarginStart * 60;
|
||||||
|
struct tm tm_r;
|
||||||
|
struct tm *time = localtime_r(&tstart, &tm_r);
|
||||||
|
day = time->tm_mday;
|
||||||
|
start = time->tm_hour * 100 + time->tm_min;
|
||||||
|
time = localtime_r(&tstop, &tm_r);
|
||||||
|
stop = time->tm_hour * 100 + time->tm_min;
|
||||||
|
if (stop >= 2400)
|
||||||
|
stop -= 2400;
|
||||||
|
priority = Setup.DefaultPriority;
|
||||||
|
lifetime = Setup.DefaultLifetime;
|
||||||
|
*file = 0;
|
||||||
|
const char *Title = EventInfo->GetTitle();
|
||||||
|
if (!isempty(Title))
|
||||||
|
strn0cpy(file, EventInfo->GetTitle(), sizeof(file));
|
||||||
|
firstday = 0;
|
||||||
|
summary = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cTimer::~cTimer()
|
||||||
|
{
|
||||||
|
free(summary);
|
||||||
|
}
|
||||||
|
|
||||||
|
cTimer& cTimer::operator= (const cTimer &Timer)
|
||||||
|
{
|
||||||
|
memcpy(this, &Timer, sizeof(*this));
|
||||||
|
if (summary)
|
||||||
|
summary = strdup(summary);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cTimer::operator< (const cListObject &ListObject)
|
||||||
|
{
|
||||||
|
cTimer *ti = (cTimer *)&ListObject;
|
||||||
|
time_t t1 = StartTime();
|
||||||
|
time_t t2 = ti->StartTime();
|
||||||
|
return t1 < t2 || (t1 == t2 && priority > ti->priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *cTimer::ToText(cTimer *Timer)
|
||||||
|
{
|
||||||
|
free(buffer);
|
||||||
|
strreplace(Timer->file, ':', '|');
|
||||||
|
strreplace(Timer->summary, '\n', '|');
|
||||||
|
asprintf(&buffer, "%d:%d:%s:%04d:%04d:%d:%d:%s:%s\n", Timer->active, Timer->Channel()->Number(), PrintDay(Timer->day, Timer->firstday), Timer->start, Timer->stop, Timer->priority, Timer->lifetime, Timer->file, Timer->summary ? Timer->summary : "");
|
||||||
|
strreplace(Timer->summary, '|', '\n');
|
||||||
|
strreplace(Timer->file, '|', ':');
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *cTimer::ToText(void)
|
||||||
|
{
|
||||||
|
return ToText(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cTimer::TimeToInt(int t)
|
||||||
|
{
|
||||||
|
return (t / 100 * 60 + t % 100) * 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cTimer::ParseDay(const char *s, time_t *FirstDay)
|
||||||
|
{
|
||||||
|
char *tail;
|
||||||
|
int d = strtol(s, &tail, 10);
|
||||||
|
if (FirstDay)
|
||||||
|
*FirstDay = 0;
|
||||||
|
if (tail && *tail) {
|
||||||
|
d = 0;
|
||||||
|
if (tail == s) {
|
||||||
|
const char *first = strchr(s, '@');
|
||||||
|
int l = first ? first - s : strlen(s);
|
||||||
|
if (l == 7) {
|
||||||
|
for (const char *p = s + 6; p >= s; p--) {
|
||||||
|
d <<= 1;
|
||||||
|
d |= (*p != '-');
|
||||||
|
}
|
||||||
|
d |= 0x80000000;
|
||||||
|
}
|
||||||
|
if (FirstDay && first) {
|
||||||
|
++first;
|
||||||
|
if (strlen(first) == 10) {
|
||||||
|
struct tm tm_r;
|
||||||
|
if (3 == sscanf(first, "%d-%d-%d", &tm_r.tm_year, &tm_r.tm_mon, &tm_r.tm_mday)) {
|
||||||
|
tm_r.tm_year -= 1900;
|
||||||
|
tm_r.tm_mon--;
|
||||||
|
tm_r.tm_hour = tm_r.tm_min = tm_r.tm_sec = 0;
|
||||||
|
tm_r.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting
|
||||||
|
*FirstDay = mktime(&tm_r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
d = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (d < 1 || d > 31)
|
||||||
|
d = 0;
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *cTimer::PrintDay(int d, time_t FirstDay)
|
||||||
|
{
|
||||||
|
#define DAYBUFFERSIZE 32
|
||||||
|
static char buffer[DAYBUFFERSIZE];
|
||||||
|
if ((d & 0x80000000) != 0) {
|
||||||
|
char *b = buffer;
|
||||||
|
const char *w = tr("MTWTFSS");
|
||||||
|
while (*w) {
|
||||||
|
*b++ = (d & 1) ? *w : '-';
|
||||||
|
d >>= 1;
|
||||||
|
w++;
|
||||||
|
}
|
||||||
|
if (FirstDay) {
|
||||||
|
struct tm tm_r;
|
||||||
|
localtime_r(&FirstDay, &tm_r);
|
||||||
|
b += strftime(b, DAYBUFFERSIZE - (b - buffer), "@%Y-%m-%d", &tm_r);
|
||||||
|
}
|
||||||
|
*b = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
sprintf(buffer, "%d", d);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *cTimer::PrintFirstDay(void)
|
||||||
|
{
|
||||||
|
if (firstday) {
|
||||||
|
const char *s = PrintDay(day, firstday);
|
||||||
|
if (strlen(s) == 18)
|
||||||
|
return s + 8;
|
||||||
|
}
|
||||||
|
return ""; // not NULL, so the caller can always use the result
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cTimer::Parse(const char *s)
|
||||||
|
{
|
||||||
|
char *buffer1 = NULL;
|
||||||
|
char *buffer2 = NULL;
|
||||||
|
free(summary);
|
||||||
|
summary = NULL;
|
||||||
|
//XXX Apparently sscanf() doesn't work correctly if the last %a argument
|
||||||
|
//XXX results in an empty string (this first occured when the EIT gathering
|
||||||
|
//XXX was put into a separate thread - don't know why this happens...
|
||||||
|
//XXX As a cure we copy the original string and add a blank.
|
||||||
|
//XXX If anybody can shed some light on why sscanf() failes here, I'd love
|
||||||
|
//XXX to hear about that!
|
||||||
|
char *s2 = NULL;
|
||||||
|
int l2 = strlen(s);
|
||||||
|
while (l2 > 0 && isspace(s[l2 - 1]))
|
||||||
|
l2--;
|
||||||
|
if (s[l2 - 1] == ':') {
|
||||||
|
s2 = MALLOC(char, l2 + 3);
|
||||||
|
strcat(strn0cpy(s2, s, l2 + 1), " \n");
|
||||||
|
s = s2;
|
||||||
|
}
|
||||||
|
int ch = 0;
|
||||||
|
if (8 <= sscanf(s, "%d :%d :%a[^:]:%d :%d :%d :%d :%a[^:\n]:%a[^\n]", &active, &ch, &buffer1, &start, &stop, &priority, &lifetime, &buffer2, &summary)) {
|
||||||
|
if (summary && !*skipspace(summary)) {
|
||||||
|
free(summary);
|
||||||
|
summary = NULL;
|
||||||
|
}
|
||||||
|
//TODO add more plausibility checks
|
||||||
|
day = ParseDay(buffer1, &firstday);
|
||||||
|
strn0cpy(file, buffer2, MaxFileName);
|
||||||
|
strreplace(file, '|', ':');
|
||||||
|
strreplace(summary, '|', '\n');
|
||||||
|
free(buffer1);
|
||||||
|
free(buffer2);
|
||||||
|
free(s2);
|
||||||
|
channel = Channels.GetByNumber(ch);
|
||||||
|
if (!channel) {
|
||||||
|
esyslog("ERROR: channel %d not defined", ch);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return day != 0;
|
||||||
|
}
|
||||||
|
free(s2);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cTimer::Save(FILE *f)
|
||||||
|
{
|
||||||
|
return fprintf(f, ToText()) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cTimer::IsSingleEvent(void)
|
||||||
|
{
|
||||||
|
return (day & 0x80000000) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cTimer::GetMDay(time_t t)
|
||||||
|
{
|
||||||
|
struct tm tm_r;
|
||||||
|
return localtime_r(&t, &tm_r)->tm_mday;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cTimer::GetWDay(time_t t)
|
||||||
|
{
|
||||||
|
struct tm tm_r;
|
||||||
|
int weekday = localtime_r(&t, &tm_r)->tm_wday;
|
||||||
|
return weekday == 0 ? 6 : weekday - 1; // we start with monday==0!
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cTimer::DayMatches(time_t t)
|
||||||
|
{
|
||||||
|
return IsSingleEvent() ? GetMDay(t) == day : (day & (1 << GetWDay(t))) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t cTimer::IncDay(time_t t, int Days)
|
||||||
|
{
|
||||||
|
struct tm tm_r;
|
||||||
|
tm tm = *localtime_r(&t, &tm_r);
|
||||||
|
tm.tm_mday += Days; // now tm_mday may be out of its valid range
|
||||||
|
int h = tm.tm_hour; // save original hour to compensate for DST change
|
||||||
|
tm.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting
|
||||||
|
t = mktime(&tm); // normalize all values
|
||||||
|
tm.tm_hour = h; // compensate for DST change
|
||||||
|
return mktime(&tm); // calculate final result
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t cTimer::SetTime(time_t t, int SecondsFromMidnight)
|
||||||
|
{
|
||||||
|
struct tm tm_r;
|
||||||
|
tm tm = *localtime_r(&t, &tm_r);
|
||||||
|
tm.tm_hour = SecondsFromMidnight / 3600;
|
||||||
|
tm.tm_min = (SecondsFromMidnight % 3600) / 60;
|
||||||
|
tm.tm_sec = SecondsFromMidnight % 60;
|
||||||
|
tm.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting
|
||||||
|
return mktime(&tm);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *cTimer::SetFile(const char *File)
|
||||||
|
{
|
||||||
|
if (!isempty(File))
|
||||||
|
strn0cpy(file, File, sizeof(file));
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cTimer::Matches(time_t t)
|
||||||
|
{
|
||||||
|
startTime = stopTime = 0;
|
||||||
|
if (t == 0)
|
||||||
|
t = time(NULL);
|
||||||
|
|
||||||
|
int begin = TimeToInt(start); // seconds from midnight
|
||||||
|
int length = TimeToInt(stop) - begin;
|
||||||
|
if (length < 0)
|
||||||
|
length += SECSINDAY;
|
||||||
|
|
||||||
|
int DaysToCheck = IsSingleEvent() ? 61 : 7; // 61 to handle months with 31/30/31
|
||||||
|
for (int i = -1; i <= DaysToCheck; i++) {
|
||||||
|
time_t t0 = IncDay(t, i);
|
||||||
|
if (DayMatches(t0)) {
|
||||||
|
time_t a = SetTime(t0, begin);
|
||||||
|
time_t b = a + length;
|
||||||
|
if ((!firstday || a >= firstday) && t <= b) {
|
||||||
|
startTime = a;
|
||||||
|
stopTime = b;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!startTime)
|
||||||
|
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
|
||||||
|
firstday = 0;
|
||||||
|
return active && startTime <= t && t < stopTime; // must stop *before* stopTime to allow adjacent timers
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t cTimer::StartTime(void)
|
||||||
|
{
|
||||||
|
if (!startTime)
|
||||||
|
Matches();
|
||||||
|
return startTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t cTimer::StopTime(void)
|
||||||
|
{
|
||||||
|
if (!stopTime)
|
||||||
|
Matches();
|
||||||
|
return stopTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cTimer::SetRecording(bool Recording)
|
||||||
|
{
|
||||||
|
recording = Recording;
|
||||||
|
isyslog("timer %d %s", Index() + 1, recording ? "start" : "stop");
|
||||||
|
}
|
||||||
|
|
||||||
|
void cTimer::SetPending(bool Pending)
|
||||||
|
{
|
||||||
|
pending = Pending;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cTimer::SetActive(int Active)
|
||||||
|
{
|
||||||
|
active = Active;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cTimer::Skip(void)
|
||||||
|
{
|
||||||
|
firstday = IncDay(SetTime(StartTime(), 0), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cTimer::OnOff(void)
|
||||||
|
{
|
||||||
|
if (IsSingleEvent())
|
||||||
|
active = !active;
|
||||||
|
else if (firstday) {
|
||||||
|
firstday = 0;
|
||||||
|
active = false;
|
||||||
|
}
|
||||||
|
else if (active)
|
||||||
|
Skip();
|
||||||
|
else
|
||||||
|
active = true;
|
||||||
|
Matches(); // refresh start and end time
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- cTimers ----------------------------------------------------------------
|
||||||
|
|
||||||
|
cTimers Timers;
|
||||||
|
|
||||||
|
cTimer *cTimers::GetTimer(cTimer *Timer)
|
||||||
|
{
|
||||||
|
for (cTimer *ti = First(); ti; ti = Next(ti)) {
|
||||||
|
if (ti->Channel() == Timer->Channel() && ti->Day() == Timer->Day() && ti->Start() == Timer->Start() && ti->Stop() == Timer->Stop())
|
||||||
|
return ti;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cTimer *cTimers::GetMatch(time_t t)
|
||||||
|
{
|
||||||
|
cTimer *t0 = NULL;
|
||||||
|
for (cTimer *ti = First(); ti; ti = Next(ti)) {
|
||||||
|
if (!ti->Recording() && ti->Matches(t)) {
|
||||||
|
if (!t0 || ti->Priority() > t0->Priority())
|
||||||
|
t0 = ti;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return t0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cTimer *cTimers::GetNextActiveTimer(void)
|
||||||
|
{
|
||||||
|
cTimer *t0 = NULL;
|
||||||
|
for (cTimer *ti = First(); ti; ti = Next(ti)) {
|
||||||
|
if (ti->Active() && (!t0 || *ti < *t0))
|
||||||
|
t0 = ti;
|
||||||
|
}
|
||||||
|
return t0;
|
||||||
|
}
|
91
timers.h
Normal file
91
timers.h
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* timers.h: Timer handling
|
||||||
|
*
|
||||||
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
|
* how to reach the author.
|
||||||
|
*
|
||||||
|
* $Id: timers.h 1.1 2002/10/20 11:52:23 kls Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __TIMERS_H
|
||||||
|
#define __TIMERS_H
|
||||||
|
|
||||||
|
#include "channels.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "tools.h"
|
||||||
|
|
||||||
|
enum eTimerActive { taInactive = 0,
|
||||||
|
taActive = 1,
|
||||||
|
taInstant = 2,
|
||||||
|
taActInst = (taActive | taInstant)
|
||||||
|
};
|
||||||
|
|
||||||
|
class cTimer : public cListObject {
|
||||||
|
friend class cMenuEditTimer;
|
||||||
|
private:
|
||||||
|
time_t startTime, stopTime;
|
||||||
|
static char *buffer;
|
||||||
|
bool recording, pending;
|
||||||
|
int active;
|
||||||
|
cChannel *channel;
|
||||||
|
int day;
|
||||||
|
int start;
|
||||||
|
int stop;
|
||||||
|
int priority;
|
||||||
|
int lifetime;
|
||||||
|
char file[MaxFileName];
|
||||||
|
time_t firstday;
|
||||||
|
char *summary;
|
||||||
|
static const char *ToText(cTimer *Timer);
|
||||||
|
public:
|
||||||
|
cTimer(bool Instant = false);
|
||||||
|
cTimer(const cEventInfo *EventInfo);
|
||||||
|
virtual ~cTimer();
|
||||||
|
cTimer& operator= (const cTimer &Timer);
|
||||||
|
virtual bool operator< (const cListObject &ListObject);
|
||||||
|
bool Recording(void) { return recording; }
|
||||||
|
bool Pending(void) { return pending; }
|
||||||
|
int Active(void) { return active; }
|
||||||
|
const cChannel *Channel(void) { return channel; }
|
||||||
|
int Day(void) { return day; }
|
||||||
|
int Start(void) { return start; }
|
||||||
|
int Stop(void) { return stop; }
|
||||||
|
int Priority(void) { return priority; }
|
||||||
|
int Lifetime(void) { return lifetime; }
|
||||||
|
const char *File(void) { return file; }
|
||||||
|
time_t FirstDay(void) { return firstday; }
|
||||||
|
const char *Summary(void) { return summary; }
|
||||||
|
const char *ToText(void);
|
||||||
|
bool Parse(const char *s);
|
||||||
|
bool Save(FILE *f);
|
||||||
|
bool IsSingleEvent(void);
|
||||||
|
int GetMDay(time_t t);
|
||||||
|
int GetWDay(time_t t);
|
||||||
|
bool DayMatches(time_t t);
|
||||||
|
static time_t IncDay(time_t t, int Days);
|
||||||
|
static time_t SetTime(time_t t, int SecondsFromMidnight);
|
||||||
|
char *SetFile(const char *File);
|
||||||
|
bool Matches(time_t t = 0);
|
||||||
|
time_t StartTime(void);
|
||||||
|
time_t StopTime(void);
|
||||||
|
void SetRecording(bool Recording);
|
||||||
|
void SetPending(bool Pending);
|
||||||
|
void SetActive(int Active);
|
||||||
|
void Skip(void);
|
||||||
|
void OnOff(void);
|
||||||
|
const char *PrintFirstDay(void);
|
||||||
|
static int TimeToInt(int t);
|
||||||
|
static int ParseDay(const char *s, time_t *FirstDay = NULL);
|
||||||
|
static const char *PrintDay(int d, time_t FirstDay = 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
class cTimers : public cConfig<cTimer> {
|
||||||
|
public:
|
||||||
|
cTimer *GetTimer(cTimer *Timer);
|
||||||
|
cTimer *GetMatch(time_t t);
|
||||||
|
cTimer *GetNextActiveTimer(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern cTimers Timers;
|
||||||
|
|
||||||
|
#endif //__TIMERS_H
|
7
vdr.c
7
vdr.c
@ -22,7 +22,7 @@
|
|||||||
*
|
*
|
||||||
* The project's page is at http://www.cadsoft.de/people/kls/vdr
|
* The project's page is at http://www.cadsoft.de/people/kls/vdr
|
||||||
*
|
*
|
||||||
* $Id: vdr.c 1.127 2002/10/13 12:13:19 kls Exp $
|
* $Id: vdr.c 1.128 2002/10/20 12:09:45 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
@ -47,6 +47,7 @@
|
|||||||
#include "rcu.h"
|
#include "rcu.h"
|
||||||
#include "recording.h"
|
#include "recording.h"
|
||||||
#include "sources.h"
|
#include "sources.h"
|
||||||
|
#include "timers.h"
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
#include "videodir.h"
|
#include "videodir.h"
|
||||||
|
|
||||||
@ -603,8 +604,8 @@ int main(int argc, char *argv[])
|
|||||||
if (WatchdogTimeout > 0)
|
if (WatchdogTimeout > 0)
|
||||||
signal(SIGALRM, SIG_IGN);
|
signal(SIGALRM, SIG_IGN);
|
||||||
if (Interface->Confirm(tr("Press any key to cancel shutdown"), UserShutdown ? 5 : SHUTDOWNWAIT, true)) {
|
if (Interface->Confirm(tr("Press any key to cancel shutdown"), UserShutdown ? 5 : SHUTDOWNWAIT, true)) {
|
||||||
int Channel = timer ? timer->channel : 0;
|
int Channel = timer ? timer->Channel()->Number() : 0;
|
||||||
const char *File = timer ? timer->file : "";
|
const char *File = timer ? timer->File() : "";
|
||||||
char *cmd;
|
char *cmd;
|
||||||
asprintf(&cmd, "%s %ld %ld %d \"%s\" %d", Shutdown, Next, Delta, Channel, strescape(File, "\"$"), UserShutdown);
|
asprintf(&cmd, "%s %ld %ld %d \"%s\" %d", Shutdown, Next, Delta, Channel, strescape(File, "\"$"), UserShutdown);
|
||||||
isyslog("executing '%s'", cmd);
|
isyslog("executing '%s'", cmd);
|
||||||
|
Loading…
Reference in New Issue
Block a user