void dvr_event_updated(epg_broadcast_t *e);
void dvr_event_running(epg_broadcast_t *e, epg_running_t running);
+int dvr_entry_assign_broadcast(dvr_entry_t *de, epg_broadcast_t *bcast);
dvr_entry_t *dvr_entry_find_by_id(int id);
void dvr_autorec_done(void);
void dvr_autorec_update(void);
-/// Check autorec timers after a short delay.
+/* Check autorec timers after a short delay. */
void dvr_autorec_async_reschedule(void);
+/* @return 1 if the event 'e' is matched by the autorec rule 'dae' */
+int dvr_autorec_cmp(dvr_autorec_entry_t *dae, epg_broadcast_t *e);
+/* Purge any autorec timers that are obsolete since they no longer match any events. */
+void dvr_autorec_purge_obsolete_timers(void);
+/* @return 1 if entry is an autorec and can be purged since it no longer matches its event. */
+int dvr_autorec_entry_can_be_purged(const dvr_entry_t *de);
+
static inline int
dvr_autorec_entry_verify(dvr_autorec_entry_t *dae, access_t *a, int readonly)
{
return bcast;
}
+
+/**
+ * If autorec entry no longer matches autorec rule then it can be purged.
+ * @return 1 if it can be purged
+ */
+int
+dvr_autorec_entry_can_be_purged(const dvr_entry_t *de)
+{
+ /* Not an autorec so ignore */
+ if (!de->de_autorec)
+ return 0;
+
+ /* Entry is not scheduled (for example finished) so can not be purged */
+ if (de->de_sched_state != DVR_SCHEDULED)
+ return 0;
+
+ /* No broadcast matched when entry was reloaded from dvr/log */
+ if (!de->de_bcast)
+ return 1;
+
+ /* Confirm autorec still matches the broadcast */
+ return !dvr_autorec_cmp(de->de_autorec, de->de_bcast);
+}
+
+/**
+ * Purge any dvr_entry for autorec entries that
+ * no longer match the current schedule.
+ */
+void
+dvr_autorec_purge_obsolete_timers(void)
+{
+ dvr_entry_t *de;
+ int num_purged = 0;
+
+ LIST_FOREACH(de, &dvrentries, de_global_link) {
+ if (dvr_autorec_entry_can_be_purged(de)) {
+ char ubuf[UUID_HEX_SIZE];
+ char t1buf[32], t2buf[32];
+ tvhinfo(LS_DVR, "Entry %s can be purged for \"%s\" start %s stop %s",
+ idnode_uuid_as_str(&de->de_id, ubuf),
+ lang_str_get(de->de_title, NULL),
+ gmtime2local(de->de_start, t1buf, sizeof(t1buf)),
+ gmtime2local(de->de_stop, t2buf, sizeof(t2buf)));
+
+ dvr_entry_assign_broadcast(de, NULL);
+ dvr_entry_destroy(de, 1);
+ ++num_purged;
+ }
+ }
+ if (num_purged)
+ tvhinfo(LS_DVR, "Purged %d autorec entries that no longer match schedule", num_purged);
+}
+
+
/**
* Handle maxcount
*/
/**
* return 1 if the event 'e' is matched by the autorec rule 'dae'
*/
-static int
-autorec_cmp(dvr_autorec_entry_t *dae, epg_broadcast_t *e)
+int
+dvr_autorec_cmp(dvr_autorec_entry_t *dae, epg_broadcast_t *e)
{
idnode_list_mapping_t *ilm;
dvr_config_t *cfg;
double duration;
+ if (!e) return 0;
if (!e->channel) return 0;
if(dae->dae_enabled == 0 || dae->dae_weekdays == 0)
return 0;
if (e->channel && !e->channel->ch_enabled)
return;
TAILQ_FOREACH(dae, &autorec_entries, dae_link)
- if(autorec_cmp(dae, e))
+ if(dvr_autorec_cmp(dae, e))
dvr_entry_create_by_autorec(1, e, dae);
// Note: no longer updating event here as it will be done from EPG
// anyway
CHANNEL_FOREACH(ch) {
if (!ch->ch_enabled) continue;
RB_FOREACH(e, &ch->ch_epg_schedule, sched_link) {
- if(autorec_cmp(dae, e)) {
+ if(dvr_autorec_cmp(dae, e)) {
enabled = 1;
if (disabled) {
for (p = disabled; *p && *p != e; p++);
/*
*
*/
-static int
+int
dvr_entry_assign_broadcast(dvr_entry_t *de, epg_broadcast_t *bcast)
{
char id[16];
updated ? " Timer" : "",
dvr_updated_str(buf, sizeof(buf), save));
}
+ /* The updates could mean the autorec rule no longer matches the event,
+ * so we have to destroy the de and the conf and let the autorec rule
+ * re-create when it next matches.
+ *
+ * If de is not scheduled (i.e., recording) then do nothing with the
+ * rule since don't want to cancel items that are recording.
+ * Also if no event then this autorec can't match it so we should delete
+ * it.
+ */
+ if (dvr_autorec_entry_can_be_purged(de)) {
+ dvr_entry_assign_broadcast(de, NULL);
+ dvr_entry_destroy(de, 1);
+ }
}
return de;
}
htsmsg_destroy(l);
}
+ /* We update the autorec entries so any that are no longer matching
+ * the current schedule get deleted. This avoids the problem where
+ * autorec entries remain even when user has deleted the epgdb
+ * or modified their settings between runs.
+ */
+ tvhinfo(LS_DVR, "Purging obsolete autorec entries for current schedule");
+ dvr_autorec_purge_obsolete_timers();
dvr_in_init = 0;
/* process parent/child mapping */
HTSMSG_FOREACH(f, rere) {