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:
parent
8f1419fff5
commit
23d986657a
4
HISTORY
4
HISTORY
@ -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
3
MANUAL
@ -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
|
||||||
|
63
timers.c
63
timers.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: 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)
|
||||||
|
8
timers.h
8
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 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
6
vdr.c
@ -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();
|
||||||
|
Loading…
Reference in New Issue
Block a user