From 3e4389b5648e7807acad0c7597bd1e173f6e143a Mon Sep 17 00:00:00 2001 From: Adam Sutton Date: Fri, 8 Mar 2013 17:26:05 +0000 Subject: [PATCH] Fix #1444 - dvr: ensure that DVR entries are not removed when EPG is updated 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 | 2 + src/dvr/dvr_db.c | 113 +++++++++++++++++++++++++++++++++-------------- 2 files changed, 83 insertions(+), 32 deletions(-) diff --git a/src/dvr/dvr.h b/src/dvr/dvr.h index 4bc56aa7..59d285cc 100644 --- a/src/dvr/dvr.h +++ b/src/dvr/dvr.h @@ -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; diff --git a/src/dvr/dvr_db.c b/src/dvr/dvr_db.c index d9cfe026..ecc2e0da 100644 --- a/src/dvr/dvr_db.c +++ b/src/dvr/dvr_db.c @@ -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 */