]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
Fix #1444 - dvr: ensure that DVR entries are not removed when EPG is updated
authorAdam Sutton <dev@adamsutton.me.uk>
Fri, 8 Mar 2013 17:26:05 +0000 (17:26 +0000)
committerAdam Sutton <dev@adamsutton.me.uk>
Tue, 26 Mar 2013 10:04:26 +0000 (10:04 +0000)
previously an overlapping (replacement) event could result in the DVR
entry being completely removed. This will now ensure that the original
entry is left in place (with just info and times).

It will also try and re-match with an EPG entry as and when it can.
(cherry picked from commit a0a7539a731c6e84b8e0a3a95b1c1655a12515c7)

src/dvr/dvr.h
src/dvr/dvr_db.c

index 4bc56aa754b483a7ab48f855afe419c7349f3008..59d285ccfb382046993529a717e9305ee9ec88df 100644 (file)
@@ -137,6 +137,8 @@ typedef struct dvr_entry {
   lang_str_t *de_desc;       /* Description in UTF-8 (from EPG) */
   epg_genre_t de_content_type; /* Content type (from EPG) */
 
+  uint16_t de_dvb_eid;
+
   dvr_prio_t de_pri;
 
   uint32_t de_dont_reschedule;
index d9cfe026c5a5615be45b56f7ecd67fe912f21749..ecc2e0da78779365cb466f7a0a184282128452ea 100644 (file)
@@ -250,6 +250,39 @@ dvr_entry_link(dvr_entry_t *de)
   htsp_dvr_entry_add(de);
 }
 
+/**
+ * Find dvr entry using 'fuzzy' search
+ */
+static int
+dvr_entry_fuzzy_match(dvr_entry_t *de, epg_broadcast_t *e)
+{
+  time_t t1, t2;
+  const char *title1, *title2;
+
+  /* Matching ID */
+  if (de->de_dvb_eid && de->de_dvb_eid == e->dvb_eid)
+    return 1;
+
+  /* No title */
+  if (!(title1 = epg_broadcast_get_title(e, NULL)))
+    return 0;
+  if (!(title2 = lang_str_get(de->de_title, NULL)))
+    return 0;
+
+  /* Wrong length (+/-20%) */
+  t1 = de->de_stop - de->de_start;
+  t2  = e->stop - e->start;
+  if ( abs(t2 - t1) > (t1 / 5) )
+    return 0;
+
+  /* Outside of window (should it be configurable)? */
+  if ( abs(e->start - de->de_start) > 86400 )
+    return 0;
+  
+  /* Title match (or contains?) */
+  return strcmp(title1, title2) == 0;
+}
+
 /**
  * Create the event
  */
@@ -301,6 +334,7 @@ static dvr_entry_t *_dvr_entry_create (
   de->de_desc  = NULL;
   // TODO: this really needs updating
   if (e) {
+    de->de_dvb_eid = e->dvb_eid;
     if (e->episode && e->episode->title)
       de->de_title = lang_str_copy(e->episode->title);
     if (e->description)
@@ -478,7 +512,7 @@ dvr_db_load_one(htsmsg_t *c, int id)
   dvr_entry_t *de;
   const char *chname, *s, *creator;
   channel_t *ch;
-  uint32_t start, stop, bcid;
+  uint32_t start, stop, bcid, u32;
   int d;
   dvr_config_t *cfg;
   lang_str_t *title, *ls;
@@ -519,6 +553,8 @@ dvr_db_load_one(htsmsg_t *c, int id)
   de->de_creator = strdup(creator);
   de->de_title   = title;
   de->de_pri     = dvr_pri2val(htsmsg_get_str(c, "pri"));
+  if (!htsmsg_get_u32(c, "dvb_eid", &u32))
+    de->de_dvb_eid = (uint16_t)u32;
   
   if(htsmsg_get_s32(c, "start_extra", &d))
     if (ch && ch->ch_dvr_extra_time_pre)
@@ -619,6 +655,9 @@ dvr_entry_save(dvr_entry_t *de)
 
   lang_str_serialize(de->de_title, m, "title");
 
+  if(de->de_dvb_eid)
+    htsmsg_add_u32(m, "dvb_eid", de->de_dvb_eid);
+
   if(de->de_desc != NULL)
     lang_str_serialize(de->de_desc, m, "description");
 
@@ -696,6 +735,12 @@ static dvr_entry_t *_dvr_entry_update
     if (!de->de_title) de->de_title = lang_str_create();
     save = lang_str_add(de->de_title, title, lang, 1);
   }
+  
+  /* EID */
+  if (e && e->dvb_eid != de->de_dvb_eid) {
+    de->de_dvb_eid = e->dvb_eid;
+    save = 1;
+  }
 
   // TODO: description
 
@@ -710,7 +755,8 @@ static dvr_entry_t *_dvr_entry_update
 
   /* Broadcast */
   if (e && (de->de_bcast != e)) {
-    de->de_bcast->putref(de->de_bcast);
+    if (de->de_bcast)
+      de->de_bcast->putref(de->de_bcast);
     de->de_bcast = e;
     e->getref(e);
     save = 1;
@@ -744,23 +790,33 @@ dvr_entry_update
 
 /**
  * Used to notify the DVR that an event has been replaced in the EPG
- *
- * TODO: I think this will record the title slot event if its now a 
- *       completely different episode etc...
  */
 void 
 dvr_event_replaced(epg_broadcast_t *e, epg_broadcast_t *new_e)
 {
-  dvr_entry_t *de, *ude;
+  dvr_entry_t *de;
+  assert(e != NULL);
+  assert(new_e != NULL);
+
+  /* Ignore */
   if ( e == new_e ) return;
 
-  de = dvr_entry_find_by_event(e);
-  if (de != NULL) {
-    ude = dvr_entry_find_by_event_fuzzy(new_e);
-    if (ude == NULL && de->de_sched_state == DVR_SCHEDULED)
-      dvr_entry_cancel(de);
-    else if(new_e->episode && new_e->episode->title)
-      _dvr_entry_update(de, new_e, NULL, NULL, NULL, 0, 0, 0, 0);
+  /* Existing entry */
+  if ((de = dvr_entry_find_by_event(e))) {
+
+    /* Unlink the broadcast */
+    e->putref(e);
+    de->de_bcast = NULL;
+
+    /* Find match */
+    RB_FOREACH(e, &e->channel->ch_epg_schedule, sched_link) {
+      if (dvr_entry_fuzzy_match(de, e)) {
+        e->getref(e);
+        de->de_bcast = e;
+        _dvr_entry_update(de, e, NULL, NULL, NULL, 0, 0, 0, 0);
+        break;
+      }
+    }
   }
 }
 
@@ -768,7 +824,18 @@ void dvr_event_updated ( epg_broadcast_t *e )
 {
   dvr_entry_t *de;
   de = dvr_entry_find_by_event(e);
-  if (de) _dvr_entry_update(de, e, NULL, NULL, NULL, 0, 0, 0, 0);
+  if (de)
+    _dvr_entry_update(de, e, NULL, NULL, NULL, 0, 0, 0, 0);
+  else {
+    LIST_FOREACH(de, &dvrentries, de_global_link) {
+      if (dvr_entry_fuzzy_match(de, e)) {
+        e->getref(e);
+        de->de_bcast = e;
+        _dvr_entry_update(de, e, NULL, NULL, NULL, 0, 0, 0, 0);
+        break;
+      }
+    }
+  }
 }
 
 /**
@@ -863,24 +930,6 @@ dvr_entry_find_by_event(epg_broadcast_t *e)
   return NULL;
 }
 
-/**
- * Find dvr entry using 'fuzzy' search
- */
-dvr_entry_t *
-dvr_entry_find_by_event_fuzzy(epg_broadcast_t *e)
-{
-  dvr_entry_t *de;
-  
-  if (!e->episode || !e->episode->title)
-    return NULL;
-
-  LIST_FOREACH(de, &e->channel->ch_dvrs, de_channel_link)
-    if ((abs(de->de_start - e->start) < 600) && (abs(de->de_stop - e->stop) < 600)) {
-        return de;
-    }
-  return NULL;
-}
-
 /*
  * Find DVR entry based on an episode
  */