1
0
mirror of https://github.com/VDR4Arch/vdr.git synced 2023-10-10 13:36:52 +02:00

Spawned timers that don't use VPS now automatically adjust their start/stop times to changes in the respective event's times

This commit is contained in:
Klaus Schmidinger 2021-04-06 08:48:35 +02:00
parent 8f1419fff5
commit 23d986657a
5 changed files with 70 additions and 14 deletions

View File

@ -9578,7 +9578,7 @@ Video Disk Recorder Revision History
given (reported by Manuel Reimer). given (reported by Manuel Reimer).
- Fixed handling $(PKG_CONFIG) in newplugin (thanks to Winfried Köhler). - Fixed handling $(PKG_CONFIG) in newplugin (thanks to Winfried Köhler).
2021-04-04: 2021-04-05:
- Fixed strreplace() to handle NULL strings (reported by Jürgen Schneider). - Fixed strreplace() to handle NULL strings (reported by Jürgen Schneider).
- Somewhere down the road the 'x' bit of Doxyfile.filter got lost, so the - Somewhere down the road the 'x' bit of Doxyfile.filter got lost, so the
@ -9633,3 +9633,5 @@ Video Disk Recorder Revision History
is changed while the recording is already going on. is changed while the recording is already going on.
- The margins for timer recordings are now always limited to the duration of the - The margins for timer recordings are now always limited to the duration of the
previous and next event. previous and next event.
- Spawned timers that don't use VPS now automatically adjust their start/stop times
to changes in the respective event's times.

3
MANUAL
View File

@ -556,6 +556,9 @@ The following rules apply to pattern timers:
- Recording is done according to the event's begin/end times, either - Recording is done according to the event's begin/end times, either
by adding the start/stop margins (for non-VPS timers) or by using the by adding the start/stop margins (for non-VPS timers) or by using the
event's running status (for VPS timers). event's running status (for VPS timers).
- If the times of the event change, a non-VPS pattern timer automatically adjusts
itself to the new times. This also happens if the start/stop margins are changed
in the setup.
- The recording of a pattern timer is stored under the given file name, just like - The recording of a pattern timer is stored under the given file name, just like
regular timers do. In addition to the "TITLE" and "EPISODE" macros the file regular timers do. In addition to the "TITLE" and "EPISODE" macros the file
name of a pattern timer can also use "{<}" and "{>}" to reference the part of the name of a pattern timer can also use "{<}" and "{>}" to reference the part of the

View File

@ -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.c 5.6 2021/04/04 13:38:13 kls Exp $ * $Id: timers.c 5.7 2021/04/06 08:48:35 kls Exp $
*/ */
#include "timers.h" #include "timers.h"
@ -27,7 +27,7 @@ cTimer::cTimer(bool Instant, bool Pause, const cChannel *Channel)
{ {
id = 0; id = 0;
startTime = stopTime = 0; startTime = stopTime = 0;
scheduleState = -1; scheduleStateSet = scheduleStateSpawn = scheduleStateAdjust = -1;
deferred = 0; deferred = 0;
pending = inVpsMargin = false; pending = inVpsMargin = false;
flags = tfNone; flags = tfNone;
@ -176,7 +176,7 @@ cTimer::cTimer(const cEvent *Event, const char *FileName, const cTimer *PatternT
{ {
id = 0; id = 0;
startTime = stopTime = 0; startTime = stopTime = 0;
scheduleState = -1; scheduleStateSet = scheduleStateSpawn = scheduleStateAdjust = -1;
deferred = 0; deferred = 0;
pending = inVpsMargin = false; pending = inVpsMargin = false;
flags = tfActive; flags = tfActive;
@ -242,7 +242,7 @@ cTimer& cTimer::operator= (const cTimer &Timer)
id = Timer.id; id = Timer.id;
startTime = Timer.startTime; startTime = Timer.startTime;
stopTime = Timer.stopTime; stopTime = Timer.stopTime;
scheduleState = -1; scheduleStateSet = scheduleStateSpawn = scheduleStateAdjust = -1;
deferred = 0; deferred = 0;
pending = Timer.pending; pending = Timer.pending;
inVpsMargin = Timer.inVpsMargin; inVpsMargin = Timer.inVpsMargin;
@ -724,7 +724,7 @@ bool cTimer::SpawnPatternTimers(const cSchedules *Schedules, cTimers *Timers)
bool TimersSpawned = false; bool TimersSpawned = false;
const cSchedule *Schedule = Schedules->GetSchedule(Channel()); const cSchedule *Schedule = Schedules->GetSchedule(Channel());
if (Schedule && Schedule->Events()->First()) { if (Schedule && Schedule->Events()->First()) {
if (Schedule->Modified(scheduleState)) { if (Schedule->Modified(scheduleStateSpawn)) {
time_t Now = time(NULL); time_t Now = time(NULL);
for (const cEvent *e = Schedule->Events()->First(); e; e = Schedule->Events()->Next(e)) { for (const cEvent *e = Schedule->Events()->First(); e; e = Schedule->Events()->Next(e)) {
if (Matches(e) != tmNone) { if (Matches(e) != tmNone) {
@ -757,6 +757,41 @@ bool cTimer::SpawnPatternTimers(const cSchedules *Schedules, cTimers *Timers)
return TimersSpawned; return TimersSpawned;
} }
bool cTimer::AdjustSpawnedTimer(void)
{
if (Event()) {
if (const cSchedule *Schedule = Event()->Schedule()) { // events may be deleted from their schedule in cSchedule::DropOutdated()!
if (Schedule->Modified(scheduleStateAdjust)) {
// Adjust the timer to shifted start/stop times of the event if necessary:
time_t tstart = Event()->StartTime();
time_t tstop = Event()->EndTime();
int MarginStart = 0;
int MarginStop = 0;
CalcMargins(MarginStart, MarginStop, Event());
tstart -= MarginStart;
tstop += MarginStop;
// Event start/end times are given in "seconds since the epoch". Some broadcasters use values
// that result in full minutes (with zero seconds), while others use any values. VDR's timers
// use times given in full minutes, truncating any seconds. Thus we only react if the start/stop
// times of the timer are off by at least one minute:
if (abs(StartTime() - tstart) >= 60 || abs(StopTime() - tstop) >= 60) {
cTimer OldTimer = *this;
struct tm tm_r;
struct tm *time = localtime_r(&tstart, &tm_r);
SetDay(cTimer::SetTime(tstart, 0));
SetStart(time->tm_hour * 100 + time->tm_min);
time = localtime_r(&tstop, &tm_r);
SetStop(time->tm_hour * 100 + time->tm_min);
Matches();
isyslog("timer %s times changed to %s-%s", *ToDescr(), *TimeString(tstart), *TimeString(tstop));
return true;
}
}
}
}
return false;
}
void cTimer::TriggerRespawn(void) void cTimer::TriggerRespawn(void)
{ {
if (HasFlags(tfSpawned) || IsPatternTimer()) { if (HasFlags(tfSpawned) || IsPatternTimer()) {
@ -777,7 +812,7 @@ bool cTimer::SetEventFromSchedule(const cSchedules *Schedules)
return SetEvent(NULL); return SetEvent(NULL);
const cSchedule *Schedule = Schedules->GetSchedule(Channel()); const cSchedule *Schedule = Schedules->GetSchedule(Channel());
if (Schedule && Schedule->Events()->First()) { if (Schedule && Schedule->Events()->First()) {
if (Schedule->Modified(scheduleState)) { if (Schedule->Modified(scheduleStateSet)) {
const cEvent *Event = NULL; const cEvent *Event = NULL;
if (HasFlags(tfVps) && Schedule->Events()->First()->Vps()) { if (HasFlags(tfVps) && Schedule->Events()->First()->Vps()) {
// VPS timers only match if their start time exactly matches the event's VPS time: // VPS timers only match if their start time exactly matches the event's VPS time:
@ -828,11 +863,11 @@ bool cTimer::SetEvent(const cEvent *Event)
if (Event) { if (Event) {
isyslog("timer %s set to event %s", *ToDescr(), *Event->ToDescr()); isyslog("timer %s set to event %s", *ToDescr(), *Event->ToDescr());
Event->IncNumTimers(); Event->IncNumTimers();
Event->Schedule()->Modified(scheduleState); // to get the current state Event->Schedule()->Modified(scheduleStateSet); // to get the current state
} }
else { else {
isyslog("timer %s set to no event", *ToDescr()); isyslog("timer %s set to no event", *ToDescr());
scheduleState = -1; scheduleStateSet = scheduleStateSpawn = scheduleStateAdjust = -1;
} }
event = Event; event = Event;
return true; return true;
@ -1132,6 +1167,18 @@ bool cTimers::SpawnPatternTimers(const cSchedules *Schedules)
return TimersModified; return TimersModified;
} }
bool cTimers::AdjustSpawnedTimers(void)
{
bool TimersModified = false;
for (cTimer *ti = First(); ti; ti = Next(ti)) {
if (ti->Local()) {
if (ti->HasFlags(tfSpawned) && !ti->HasFlags(tfVps))
TimersModified |= ti->AdjustSpawnedTimer();
}
}
return TimersModified;
}
bool cTimers::DeleteExpired(void) bool cTimers::DeleteExpired(void)
{ {
if (time(NULL) - lastDeleteExpired < 30) if (time(NULL) - lastDeleteExpired < 30)

View File

@ -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 5.3 2021/04/04 13:38:13 kls Exp $ * $Id: timers.h 5.4 2021/04/06 08:48:35 kls Exp $
*/ */
#ifndef __TIMERS_H #ifndef __TIMERS_H
@ -33,7 +33,9 @@ class cTimer : public cListObject {
private: private:
int id; int id;
mutable time_t startTime, stopTime; mutable time_t startTime, stopTime;
int scheduleState; int scheduleStateSet;
int scheduleStateSpawn;
int scheduleStateAdjust;
mutable time_t deferred; ///< Matches(time_t, ...) will return false if the current time is before this value mutable time_t deferred; ///< Matches(time_t, ...) will return false if the current time is before this value
bool pending, inVpsMargin; bool pending, inVpsMargin;
uint flags; uint flags;
@ -99,6 +101,7 @@ public:
void SetId(int Id); void SetId(int Id);
void SpawnPatternTimer(const cEvent *Event, cTimers *Timers); void SpawnPatternTimer(const cEvent *Event, cTimers *Timers);
bool SpawnPatternTimers(const cSchedules *Schedules, cTimers *Timers); bool SpawnPatternTimers(const cSchedules *Schedules, cTimers *Timers);
bool AdjustSpawnedTimer(void);
void TriggerRespawn(void); void TriggerRespawn(void);
bool SetEventFromSchedule(const cSchedules *Schedules); bool SetEventFromSchedule(const cSchedules *Schedules);
bool SetEvent(const cEvent *Event); bool SetEvent(const cEvent *Event);
@ -196,6 +199,7 @@ public:
const cTimer *UsesChannel(const cChannel *Channel) const; const cTimer *UsesChannel(const cChannel *Channel) const;
bool SetEvents(const cSchedules *Schedules); bool SetEvents(const cSchedules *Schedules);
bool SpawnPatternTimers(const cSchedules *Schedules); bool SpawnPatternTimers(const cSchedules *Schedules);
bool AdjustSpawnedTimers(void);
bool DeleteExpired(void); bool DeleteExpired(void);
void Add(cTimer *Timer, cTimer *After = NULL); void Add(cTimer *Timer, cTimer *After = NULL);
void Ins(cTimer *Timer, cTimer *Before = NULL); void Ins(cTimer *Timer, cTimer *Before = NULL);

6
vdr.c
View File

@ -22,7 +22,7 @@
* *
* The project's page is at http://www.tvdr.de * The project's page is at http://www.tvdr.de
* *
* $Id: vdr.c 5.1 2020/12/26 15:49:01 kls Exp $ * $Id: vdr.c 5.2 2021/04/06 08:48:35 kls Exp $
*/ */
#include <getopt.h> #include <getopt.h>
@ -1109,8 +1109,8 @@ int main(int argc, char *argv[])
Timers->SetSyncStateKey(StateKeySVDRPRemoteTimersPoll); // setting events shall not trigger a remote timer poll... Timers->SetSyncStateKey(StateKeySVDRPRemoteTimersPoll); // setting events shall not trigger a remote timer poll...
if (Timers->SetEvents(Schedules)) if (Timers->SetEvents(Schedules))
TimersModified = true; TimersModified = true;
if (Timers->SpawnPatternTimers(Schedules)) { if (Timers->SpawnPatternTimers(Schedules) | Timers->AdjustSpawnedTimers()) { // this really is '|', not '||'!
StateKeySVDRPRemoteTimersPoll.Reset(); // ...but spawning new timers must! StateKeySVDRPRemoteTimersPoll.Reset(); // ...but spawning new timers or adjusting spawned timers must!
TimersModified = true; TimersModified = true;
} }
SchedulesStateKey.Remove(); SchedulesStateKey.Remove();