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.
This commit is contained in:
Adam Sutton 2013-03-08 17:26:05 +00:00
parent 1508fd6166
commit a0a7539a73
2 changed files with 83 additions and 32 deletions

View 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;

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