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 */