From: Jaroslav Kysela Date: Thu, 15 Feb 2018 14:51:30 +0000 (+0100) Subject: epg: implement epg set for serieslinks and episodelinks X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2ab2672dfca6270308512c88a4e1060b12657189;p=thirdparty%2Ftvheadend.git epg: implement epg set for serieslinks and episodelinks --- diff --git a/src/api/api_epg.c b/src/api/api_epg.c index 2fba65cd5..82d4760ce 100644 --- a/src/api/api_epg.c +++ b/src/api/api_epg.c @@ -92,10 +92,10 @@ api_epg_entry ( epg_broadcast_t *eb, const char *lang, access_t *perm, const cha /* EPG IDs */ htsmsg_add_u32(m, "eventId", eb->id); - if (eb->episode_uri && strncasecmp(eb->episode_uri, "tvh://", 6)) - htsmsg_add_str(m, "episodeUri", eb->episode_uri); - if (eb->serieslink_uri) - htsmsg_add_str(m, "serieslinkUri", eb->serieslink_uri); + if (eb->episodelink && strncasecmp(eb->episodelink->uri, "tvh://", 6)) + htsmsg_add_str(m, "episodeUri", eb->episodelink->uri); + if (eb->serieslink) + htsmsg_add_str(m, "serieslinkUri", eb->serieslink->uri); /* Channel Info */ api_epg_add_channel(m, ch, *blank); @@ -512,22 +512,21 @@ api_epg_episode_broadcasts uint32_t *entries, epg_broadcast_t *ebc_skip ) { epg_broadcast_t *ebc; - channel_t *ch; htsmsg_t *m; - const char *uri = ep->episode_uri; + epg_set_t *episodelink = ep->episodelink; + epg_set_item_t *item; - if (uri == NULL || uri[0] == '\0') + if (episodelink == NULL) return; - CHANNEL_FOREACH(ch) - if (channel_access(ch, perm, 0)) - RB_FOREACH(ebc, &ch->ch_epg_schedule, sched_link) - if (ebc && ebc->episode_uri && ebc != ebc_skip && - strcmp(uri, ebc->episode_uri) == 0) { - m = api_epg_entry(ebc, lang, perm, NULL); - htsmsg_add_msg(l, NULL, m); - (*entries)++; - } + LIST_FOREACH(item, &episodelink->broadcasts, item_link) { + ebc = item->broadcast; + if (ebc != ebc_skip) { + m = api_epg_entry(ebc, lang, perm, NULL); + htsmsg_add_msg(l, NULL, m); + (*entries)++; + } + } } static int @@ -566,8 +565,9 @@ api_epg_related uint32_t id, entries = 0; htsmsg_t *l = htsmsg_create_list(), *m; epg_broadcast_t *e, *ebc; - channel_t *ch; - char *lang, *uri; + char *lang; + epg_set_t *serieslink; + epg_set_item_t *item; if (htsmsg_get_u32(args, "eventId", &id)) return -EINVAL; @@ -576,17 +576,16 @@ api_epg_related lang = access_get_lang(perm, htsmsg_get_str(args, "lang")); pthread_mutex_lock(&global_lock); e = epg_broadcast_find_by_id(id); - uri = e->serieslink_uri; - if (uri && uri[0]) { - CHANNEL_FOREACH(ch) - if (channel_access(ch, perm, 0)) - RB_FOREACH(ebc, &ch->ch_epg_schedule, sched_link) - if (ebc != e && ebc->serieslink_uri && - strcmp(ebc->serieslink_uri, uri) == 0) { - m = api_epg_entry(ebc, lang, perm, NULL); - htsmsg_add_msg(l, NULL, m); - entries++; - } + serieslink = e->serieslink; + if (serieslink) { + LIST_FOREACH(item, &serieslink->broadcasts, item_link) { + ebc = item->broadcast; + if (ebc != e) { + m = api_epg_entry(ebc, lang, perm, NULL); + htsmsg_add_msg(l, NULL, m); + entries++; + } + } } pthread_mutex_unlock(&global_lock); free(lang); diff --git a/src/dvr/dvr_autorec.c b/src/dvr/dvr_autorec.c index e140d72a9..d9d3a63c7 100644 --- a/src/dvr/dvr_autorec.c +++ b/src/dvr/dvr_autorec.c @@ -168,8 +168,8 @@ autorec_cmp(dvr_autorec_entry_t *dae, epg_broadcast_t *e) return 0; // Avoid super wildcard match if(dae->dae_serieslink_uri) { - if (!e->serieslink_uri || - strcmp(dae->dae_serieslink_uri ?: "", e->serieslink_uri)) return 0; + if (!e->serieslink || + strcmp(dae->dae_serieslink_uri ?: "", e->serieslink->uri)) return 0; } if(dae->dae_btype != DVR_AUTOREC_BTYPE_ALL) { @@ -401,8 +401,8 @@ dvr_autorec_add_series_link(const char *dvr_config_name, free(title); htsmsg_add_str(conf, "config_name", dvr_config_name ?: ""); htsmsg_add_str(conf, "channel", chname); - if (event->serieslink_uri) - htsmsg_add_str(conf, "serieslink", event->serieslink_uri); + if (event->serieslink) + htsmsg_add_str(conf, "serieslink", event->serieslink->uri); htsmsg_add_str(conf, "owner", owner ?: ""); htsmsg_add_str(conf, "creator", creator ?: ""); htsmsg_add_str(conf, "comment", comment ?: ""); diff --git a/src/dvr/dvr_db.c b/src/dvr/dvr_db.c index 6fdf9d441..9d7ed6093 100644 --- a/src/dvr/dvr_db.c +++ b/src/dvr/dvr_db.c @@ -1059,8 +1059,8 @@ dvr_entry_create_from_htsmsg(htsmsg_t *conf, epg_broadcast_t *e) htsmsg_add_str(conf, "episode", s); if (e->copyright_year) htsmsg_add_u32(conf, "copyright_year", e->copyright_year); - if (e->episode_uri) - htsmsg_add_str(conf, "uri", e->episode_uri); + if (e->episodelink) + htsmsg_add_str(conf, "uri", e->episodelink->uri); if (e->image) htsmsg_add_str(conf, "image", e->image); genre = LIST_FIRST(&e->genre); @@ -1099,7 +1099,7 @@ static time_t dvr_entry_get_segment_stop_extra( dvr_entry_t *de ) time_t segment_stop_extra, start, stop, maximum_stop_time; int max_progs_to_check; epg_broadcast_t *e, *next; - const char *ep_uri, *next_uri; + epg_set_t *eplink1, *eplink2; if (!de) return 0; @@ -1119,10 +1119,12 @@ static time_t dvr_entry_get_segment_stop_extra( dvr_entry_t *de ) return 0; } - ep_uri = e->episode_uri; + eplink1 = e->episodelink; /* If not a segmented programme then no segment extra time */ - if (!ep_uri || strncmp(ep_uri, "crid://", 7) || !strstr(ep_uri, "#")) + if (eplink1 == NULL || + strncmp(eplink1->uri, "crid://", 7) || + !strstr(eplink1->uri, "#")) return 0; /* This URI is a CRID (from EIT) which contains an IMI so the @@ -1157,15 +1159,17 @@ static time_t dvr_entry_get_segment_stop_extra( dvr_entry_t *de ) --max_progs_to_check && stop < maximum_stop_time && next && next->start < stop + THREE_HOURS; next = epg_broadcast_get_next(next)) { - next_uri = next->episode_uri; - if (next_uri && strcmp(ep_uri, next_uri) == 0) { + eplink2 = next->episodelink; + if (eplink2 && eplink1 == eplink2) { /* Identical CRID+IMI. So that means that programme is a * segment part of this programme. So extend our stop time * to include this programme. */ segment_stop_extra = next->stop - stop; - tvhinfo(LS_DVR, "Increasing stop for \"%s\" on \"%s\" \"%s\" by %"PRId64" seconds at start %"PRId64" and original stop %"PRId64, - lang_str_get(e->title, NULL), DVR_CH_NAME(de), ep_uri, (int64_t)segment_stop_extra, (int64_t)start, (int64_t)stop); + tvhinfo(LS_DVR, "Increasing stop for \"%s\" on \"%s\" \"%s\" by %"PRId64 + " seconds at start %"PRId64" and original stop %"PRId64, + lang_str_get(e->title, NULL), DVR_CH_NAME(de), eplink1->uri, + (int64_t)segment_stop_extra, (int64_t)start, (int64_t)stop); } } diff --git a/src/epg.c b/src/epg.c index 3325b5e1b..c4b6efe9b 100644 --- a/src/epg.c +++ b/src/epg.c @@ -45,7 +45,8 @@ epg_object_tree_t epg_objects[EPG_HASH_WIDTH]; /* URI lists */ -epg_object_tree_t epg_episodes; +epg_set_tree_t epg_serieslinks; +epg_set_tree_t epg_episodelinks; /* Other special case lists */ epg_object_list_t epg_object_unref; @@ -114,7 +115,6 @@ static void _epg_object_destroy assert(eo->refcount == 0); tvhtrace(LS_EPG, "eo [%p, %u, %d] destroy", eo, eo->id, eo->type); - if (tree) RB_REMOVE(tree, eo, uri_link); if (eo->_updated) LIST_REMOVE(eo, up_link); RB_REMOVE(epg_id_tree(eo), eo, id_link); } @@ -221,10 +221,10 @@ static htsmsg_t * _epg_object_serialize ( void *o ) if (!eo->id || !eo->type) return NULL; m = htsmsg_create_map(); htsmsg_add_u32(m, "id", eo->id); - htsmsg_add_u32(m, "type", eo->type); + htsmsg_add_u32(m, "tp", eo->type); if (eo->grabber) - htsmsg_add_str(m, "grabber", eo->grabber->id); - htsmsg_add_s64(m, "updated", eo->updated); + htsmsg_add_str(m, "gr", eo->grabber->id); + htsmsg_add_s64(m, "up", eo->updated); return m; } @@ -233,12 +233,12 @@ static epg_object_t *_epg_object_deserialize ( htsmsg_t *m, epg_object_t *eo ) int64_t s64; uint32_t u32; const char *s; - if (htsmsg_get_u32(m, "id", &eo->id)) return NULL; - if (htsmsg_get_u32(m, "type", &u32)) return NULL; + if (htsmsg_get_u32(m, "id", &eo->id)) return NULL; + if (htsmsg_get_u32(m, "tp", &u32)) return NULL; if (u32 != eo->type) return NULL; - if ((s = htsmsg_get_str(m, "grabber"))) + if ((s = htsmsg_get_str(m, "gr"))) eo->grabber = epggrab_module_find_by_id(s); - if (!htsmsg_get_s64(m, "updated", &s64)) { + if (!htsmsg_get_s64(m, "up", &s64)) { _epg_object_set_updated(eo); eo->updated = s64; } @@ -349,17 +349,17 @@ htsmsg_t *epg_episode_epnum_serialize ( epg_episode_num_t *num ) if (!num) return NULL; m = htsmsg_create_map(); if (num->e_num) - htsmsg_add_u32(m, "e_num", num->e_num); + htsmsg_add_u32(m, "enum", num->e_num); if (num->e_cnt) - htsmsg_add_u32(m, "e_cnt", num->e_cnt); + htsmsg_add_u32(m, "ecnt", num->e_cnt); if (num->s_num) - htsmsg_add_u32(m, "s_num", num->s_num); + htsmsg_add_u32(m, "snum", num->s_num); if (num->s_cnt) - htsmsg_add_u32(m, "s_cnt", num->s_cnt); + htsmsg_add_u32(m, "scnt", num->s_cnt); if (num->p_num) - htsmsg_add_u32(m, "p_num", num->p_num); + htsmsg_add_u32(m, "pnum", num->p_num); if (num->p_cnt) - htsmsg_add_u32(m, "p_cnt", num->p_cnt); + htsmsg_add_u32(m, "pcnt", num->p_cnt); if (num->text) htsmsg_add_str(m, "text", num->text); return m; @@ -374,17 +374,17 @@ void epg_episode_epnum_deserialize memset(num, 0, sizeof(epg_episode_num_t)); - if (!htsmsg_get_u32(m, "e_num", &u32)) + if (!htsmsg_get_u32(m, "enum", &u32)) num->e_num = u32; - if (!htsmsg_get_u32(m, "e_cnt", &u32)) + if (!htsmsg_get_u32(m, "ecnt", &u32)) num->e_cnt = u32; - if (!htsmsg_get_u32(m, "s_num", &u32)) + if (!htsmsg_get_u32(m, "snum", &u32)) num->s_num = u32; - if (!htsmsg_get_u32(m, "s_cnt", &u32)) + if (!htsmsg_get_u32(m, "scnt", &u32)) num->s_cnt = u32; - if (!htsmsg_get_u32(m, "p_num", &u32)) + if (!htsmsg_get_u32(m, "pnum", &u32)) num->p_num = u32; - if (!htsmsg_get_u32(m, "p_cnt", &u32)) + if (!htsmsg_get_u32(m, "pcnt", &u32)) num->p_cnt = u32; if ((str = htsmsg_get_str(m, "text"))) num->text = strdup(str); @@ -747,6 +747,71 @@ epg_broadcast_t *epg_match_now_next ( channel_t *ch, epg_broadcast_t *ebc ) return ret; } +/* ************************************************************************** + * Broadcast set + * *************************************************************************/ + +static int _set_uri_cmp(const void *_a, const void *_b) +{ + const epg_set_t *a = _a, *b = _b; + return strcmp(a->uri, b->uri); +} + +epg_set_t *epg_set_broadcast_find_by_uri + (epg_set_tree_t *tree, const char *uri) +{ + epg_set_t *dummy; + + if (tree == NULL || uri == NULL || uri[0] == '\0') + return NULL; + dummy = (epg_set_t *)(uri - offsetof(epg_set_t, uri)); + return RB_FIND(tree, dummy, set_link, _set_uri_cmp); +} + + +epg_set_t *epg_set_broadcast_insert + (epg_set_tree_t *tree, epg_broadcast_t *b, const char *uri) +{ + epg_set_t *es; + epg_set_item_t *item; + + if (tree == NULL || b == NULL) + return NULL; + if (uri == NULL || uri[0] == '\0') + return NULL; + es = epg_set_broadcast_find_by_uri(tree, uri); + if (!es) { + es = malloc(sizeof(*es) + strlen(uri) + 1); + LIST_INIT(&es->broadcasts); + strcpy(es->uri, uri); + RB_INSERT_SORTED(tree, es, set_link, _set_uri_cmp); + } + item = malloc(sizeof(*item)); + item->broadcast = b; + LIST_INSERT_HEAD(&es->broadcasts, item, item_link); + return es; +} + +void epg_set_broadcast_remove + (epg_set_tree_t *tree, epg_set_t *set, epg_broadcast_t *b) +{ + epg_set_item_t *item; + + if (tree == NULL || set == NULL) + return; + LIST_FOREACH(item, &set->broadcasts, item_link) + if (item->broadcast == b) { + LIST_REMOVE(item, item_link); + free(item); + if (LIST_EMPTY(&set->broadcasts)) { + RB_REMOVE(tree, set, set_link); + free(set); + } + return; + } + assert(0); +} + /* ************************************************************************** * Broadcast * *************************************************************************/ @@ -777,8 +842,8 @@ static void _epg_broadcast_destroy ( void *eo ) if (ebc->category) string_list_destroy(ebc->category); if (ebc->keyword) string_list_destroy(ebc->keyword); if (ebc->keyword_cached) lang_str_destroy(ebc->keyword_cached); - free(ebc->serieslink_uri); - free(ebc->episode_uri); + epg_set_broadcast_remove(&epg_serieslinks, ebc->serieslink, ebc); + epg_set_broadcast_remove(&epg_episodelinks, ebc->episodelink, ebc); _epg_object_destroy(eo, NULL); assert(LIST_EMPTY(&ebc->dvr_entries)); free(ebc); @@ -875,7 +940,7 @@ int epg_broadcast_change_finish if (!(changes & EPG_CHANGED_SERIESLINK)) save |= epg_broadcast_set_serieslink_uri(broadcast, NULL, NULL); if (!(changes & EPG_CHANGED_EPISODE)) - save |= epg_broadcast_set_episode_uri(broadcast, NULL, NULL); + save |= epg_broadcast_set_episodelink_uri(broadcast, NULL, NULL); if (!(changes & EPG_CHANGED_DVB_EID)) save |= epg_broadcast_set_dvb_eid(broadcast, 0, NULL); if (!(changes & EPG_CHANGED_IS_WIDESCREEN)) @@ -976,8 +1041,10 @@ epg_broadcast_t *epg_broadcast_clone *save |= epg_broadcast_set_category(ebc, src->category, &changes); *save |= epg_broadcast_set_keyword(ebc, src->keyword, &changes); *save |= epg_broadcast_set_description(ebc, src->description, &changes); - *save |= epg_broadcast_set_serieslink_uri(ebc, src->serieslink_uri, &changes); - *save |= epg_broadcast_set_episode_uri(ebc, src->episode_uri, &changes); + *save |= epg_broadcast_set_serieslink_uri + (ebc, src->serieslink ? src->serieslink->uri : NULL, &changes); + *save |= epg_broadcast_set_episodelink_uri + (ebc, src->episodelink ? src->episodelink->uri : NULL, &changes); *save |= epg_broadcast_set_first_aired(ebc, src->first_aired, &changes); *save |= epg_broadcast_set_copyright_year(ebc, src->copyright_year, &changes); _epg_object_set_grabber(ebc, src->grabber); @@ -1012,32 +1079,38 @@ int epg_broadcast_set_running return save; } +static int _epg_broadcast_set_set + ( epg_broadcast_t *ebc, const char *uri, + epg_set_tree_t *tree, epg_set_t **set ) +{ + if (*set == NULL) { + if (uri == NULL || uri[0] == '\0') + return 0; + } else if (strcmp((*set)->uri ?: "", uri ?: "")) { + if (*set) + epg_set_broadcast_remove(tree, *set, ebc); + } else { + return 0; + } + *set = epg_set_broadcast_insert(tree, ebc, uri); + return 1; +} + + int epg_broadcast_set_serieslink_uri ( epg_broadcast_t *ebc, const char *uri, epg_changes_t *changed ) { - int save = 0; if (!ebc) return 0; if (changed) *changed |= EPG_CHANGED_SERIESLINK; - if (strcmp(ebc->serieslink_uri ?: "", uri ?: "")) { - free(ebc->serieslink_uri); - ebc->serieslink_uri = strdup(uri); - save = 1; - } - return save; + return _epg_broadcast_set_set(ebc, uri, &epg_serieslinks, &ebc->serieslink); } -int epg_broadcast_set_episode_uri +int epg_broadcast_set_episodelink_uri ( epg_broadcast_t *ebc, const char *uri, epg_changes_t *changed ) { - int save = 0; if (!ebc) return 0; - if (changed) *changed |= EPG_CHANGED_SERIESLINK; - if (strcmp(ebc->episode_uri ?: "", uri ?: "")) { - free(ebc->episode_uri); - ebc->episode_uri = strdup(uri); - save = 1; - } - return save; + if (changed) *changed |= EPG_CHANGED_EPISODE; + return _epg_broadcast_set_set(ebc, uri, &epg_episodelinks, &ebc->episodelink); } int epg_broadcast_set_dvb_eid @@ -1436,11 +1509,11 @@ htsmsg_t *epg_broadcast_serialize ( epg_broadcast_t *broadcast ) htsmsg_add_s64(m, "start", broadcast->start); htsmsg_add_s64(m, "stop", broadcast->stop); if (broadcast->channel) - htsmsg_add_str(m, "channel", channel_get_uuid(broadcast->channel, ubuf)); + htsmsg_add_str(m, "ch", channel_get_uuid(broadcast->channel, ubuf)); if (broadcast->dvb_eid) - htsmsg_add_u32(m, "dvb_eid", broadcast->dvb_eid); + htsmsg_add_u32(m, "eid", broadcast->dvb_eid); if (broadcast->is_widescreen) - htsmsg_add_u32(m, "is_widescreen", 1); + htsmsg_add_u32(m, "is_wd", 1); if (broadcast->is_hd) htsmsg_add_u32(m, "is_hd", 1); if (broadcast->is_bw) @@ -1450,49 +1523,52 @@ htsmsg_t *epg_broadcast_serialize ( epg_broadcast_t *broadcast ) if (broadcast->aspect) htsmsg_add_u32(m, "aspect", broadcast->aspect); if (broadcast->is_deafsigned) - htsmsg_add_u32(m, "is_deafsigned", 1); + htsmsg_add_u32(m, "is_de", 1); if (broadcast->is_subtitled) - htsmsg_add_u32(m, "is_subtitled", 1); + htsmsg_add_u32(m, "is_st", 1); if (broadcast->is_audio_desc) - htsmsg_add_u32(m, "is_audio_desc", 1); + htsmsg_add_u32(m, "is_ad", 1); if (broadcast->is_new) - htsmsg_add_u32(m, "is_new", 1); + htsmsg_add_u32(m, "is_n", 1); if (broadcast->is_repeat) - htsmsg_add_u32(m, "is_repeat", 1); + htsmsg_add_u32(m, "is_r", 1); if (broadcast->star_rating) - htsmsg_add_u32(m, "star_rating", broadcast->star_rating); + htsmsg_add_u32(m, "star", broadcast->star_rating); if (broadcast->age_rating) - htsmsg_add_u32(m, "age_rating", broadcast->age_rating); + htsmsg_add_u32(m, "age", broadcast->age_rating); if (broadcast->image) - htsmsg_add_str(m, "image", broadcast->image); + htsmsg_add_str(m, "img", broadcast->image); if (broadcast->title) - lang_str_serialize(broadcast->summary, m, "title"); + lang_str_serialize(broadcast->summary, m, "tit"); if (broadcast->subtitle) - lang_str_serialize(broadcast->summary, m, "subtitle"); + lang_str_serialize(broadcast->summary, m, "sti"); if (broadcast->summary) - lang_str_serialize(broadcast->summary, m, "summary"); + lang_str_serialize(broadcast->summary, m, "sum"); if (broadcast->description) - lang_str_serialize(broadcast->description, m, "description"); - htsmsg_add_msg(m, "epnum", epg_episode_epnum_serialize(&broadcast->epnum)); + lang_str_serialize(broadcast->description, m, "des"); + htsmsg_add_msg(m, "epn", epg_episode_epnum_serialize(&broadcast->epnum)); + a = NULL; LIST_FOREACH(eg, &broadcast->genre, link) { if (!a) a = htsmsg_create_list(); htsmsg_add_u32(a, NULL, eg->code); } if (a) htsmsg_add_msg(m, "genre", a); if (broadcast->copyright_year) - htsmsg_add_u32(m, "copyright_year", broadcast->copyright_year); + htsmsg_add_u32(m, "cyear", broadcast->copyright_year); if (broadcast->first_aired) - htsmsg_add_s64(m, "first_aired", broadcast->first_aired); + htsmsg_add_s64(m, "fair", broadcast->first_aired); if (broadcast->credits) - htsmsg_add_msg(m, "credits", htsmsg_copy(broadcast->credits)); + htsmsg_add_msg(m, "cred", htsmsg_copy(broadcast->credits)); /* No need to serialize credits_cached since it is rebuilt from credits. */ if (broadcast->category) - string_list_serialize(broadcast->category, m, "category"); + string_list_serialize(broadcast->category, m, "cat"); if (broadcast->keyword) - string_list_serialize(broadcast->keyword, m, "keyword"); + string_list_serialize(broadcast->keyword, m, "key"); /* No need to serialize keyword_cached since it is rebuilt from keyword */ - if (broadcast->serieslink_uri) - htsmsg_add_str(m, "serieslink", broadcast->serieslink_uri); + if (broadcast->serieslink) + htsmsg_add_str(m, "slink", broadcast->serieslink->uri); + if (broadcast->episodelink) + htsmsg_add_str(m, "elink", broadcast->episodelink->uri); return m; } @@ -1516,7 +1592,6 @@ epg_broadcast_t *epg_broadcast_deserialize if (!start || !stop) return NULL; if (stop <= start) return NULL; if (stop <= gclk()) return NULL; - if (!(str = htsmsg_get_str(m, "episode"))) return NULL; _epg_object_deserialize(m, (epg_object_t*)*skel); @@ -1525,7 +1600,7 @@ epg_broadcast_t *epg_broadcast_deserialize (*skel)->stop = stop; /* Get channel */ - if ((str = htsmsg_get_str(m, "channel"))) + if ((str = htsmsg_get_str(m, "ch"))) ch = channel_find(str); if (!ch) return NULL; @@ -1534,9 +1609,9 @@ epg_broadcast_t *epg_broadcast_deserialize if (!ebc) return NULL; /* Get metadata */ - if (!htsmsg_get_u32(m, "dvb_eid", &eid)) + if (!htsmsg_get_u32(m, "eid", &eid)) *save |= epg_broadcast_set_dvb_eid(ebc, eid, &changes); - if (!htsmsg_get_u32(m, "is_widescreen", &u32)) + if (!htsmsg_get_u32(m, "is_wd", &u32)) *save |= epg_broadcast_set_is_widescreen(ebc, u32, &changes); if (!htsmsg_get_u32(m, "is_hd", &u32)) *save |= epg_broadcast_set_is_hd(ebc, u32, &changes); @@ -1546,22 +1621,22 @@ epg_broadcast_t *epg_broadcast_deserialize *save |= epg_broadcast_set_lines(ebc, u32, &changes); if (!htsmsg_get_u32(m, "aspect", &u32)) *save |= epg_broadcast_set_aspect(ebc, u32, &changes); - if (!htsmsg_get_u32(m, "is_deafsigned", &u32)) + if (!htsmsg_get_u32(m, "is_de", &u32)) *save |= epg_broadcast_set_is_deafsigned(ebc, u32, &changes); - if (!htsmsg_get_u32(m, "is_subtitled", &u32)) + if (!htsmsg_get_u32(m, "is_st", &u32)) *save |= epg_broadcast_set_is_subtitled(ebc, u32, &changes); - if (!htsmsg_get_u32(m, "is_audio_desc", &u32)) + if (!htsmsg_get_u32(m, "is_ad", &u32)) *save |= epg_broadcast_set_is_audio_desc(ebc, u32, &changes); - if (!htsmsg_get_u32(m, "is_new", &u32)) + if (!htsmsg_get_u32(m, "is_n", &u32)) *save |= epg_broadcast_set_is_new(ebc, u32, &changes); - if (!htsmsg_get_u32(m, "is_repeat", &u32)) + if (!htsmsg_get_u32(m, "is_r", &u32)) *save |= epg_broadcast_set_is_repeat(ebc, u32, &changes); - if (!htsmsg_get_u32(m, "star_rating", &u32)) + if (!htsmsg_get_u32(m, "star", &u32)) *save |= epg_broadcast_set_star_rating(ebc, u32, &changes); - if (!htsmsg_get_u32(m, "age_rating", &u32)) + if (!htsmsg_get_u32(m, "age", &u32)) *save |= epg_broadcast_set_age_rating(ebc, u32, &changes); - if ((str = htsmsg_get_str(m, "image"))) + if ((str = htsmsg_get_str(m, "img"))) *save |= epg_broadcast_set_image(ebc, str, &changes); if ((hm = htsmsg_get_list(m, "genre"))) { @@ -1575,49 +1650,51 @@ epg_broadcast_t *epg_broadcast_deserialize epg_genre_list_destroy(egl); } - if ((ls = lang_str_deserialize(m, "title"))) { + if ((ls = lang_str_deserialize(m, "tit"))) { *save |= epg_broadcast_set_title(ebc, ls, &changes); lang_str_destroy(ls); } - if ((ls = lang_str_deserialize(m, "subtitle"))) { + if ((ls = lang_str_deserialize(m, "sti"))) { *save |= epg_broadcast_set_subtitle(ebc, ls, &changes); lang_str_destroy(ls); } - if ((ls = lang_str_deserialize(m, "summary"))) { + if ((ls = lang_str_deserialize(m, "sum"))) { *save |= epg_broadcast_set_summary(ebc, ls, &changes); lang_str_destroy(ls); } - if ((ls = lang_str_deserialize(m, "description"))) { + if ((ls = lang_str_deserialize(m, "des"))) { *save |= epg_broadcast_set_description(ebc, ls, &changes); lang_str_destroy(ls); } - if ((hm = htsmsg_get_map(m, "epnum"))) { + if ((hm = htsmsg_get_map(m, "epn"))) { epg_episode_epnum_deserialize(hm, &num); *save |= epg_broadcast_set_epnum(ebc, &num, &changes); if (num.text) free(num.text); } - if (!htsmsg_get_u32(m, "copyright_year", &u32)) + if (!htsmsg_get_u32(m, "cyear", &u32)) *save |= epg_broadcast_set_copyright_year(ebc, u32, &changes); - if (!htsmsg_get_s64(m, "first_aired", &s64)) + if (!htsmsg_get_s64(m, "fair", &s64)) *save |= epg_broadcast_set_first_aired(ebc, (time_t)s64, &changes); - if ((hm = htsmsg_get_map(m, "credits"))) + if ((hm = htsmsg_get_map(m, "cred"))) *save |= epg_broadcast_set_credits(ebc, hm, &changes); - if ((sl = string_list_deserialize(m, "keyword"))) { + if ((sl = string_list_deserialize(m, "key"))) { *save |= epg_broadcast_set_keyword(ebc, sl, &changes); string_list_destroy(sl); } - if ((sl = string_list_deserialize(m, "category"))) { + if ((sl = string_list_deserialize(m, "cat"))) { *save |= epg_broadcast_set_category(ebc, sl, &changes); string_list_destroy(sl); } /* Series link */ - if ((str = htsmsg_get_str(m, "serieslink"))) + if ((str = htsmsg_get_str(m, "slink"))) *save |= epg_broadcast_set_serieslink_uri(ebc, str, &changes); + if ((str = htsmsg_get_str(m, "elink"))) + *save |= epg_broadcast_set_episodelink_uri(ebc, str, &changes); *save |= epg_broadcast_change_finish(ebc, changes, 0); @@ -2498,4 +2575,6 @@ void epg_skel_done(void) broad = _epg_broadcast_skel(); free(*broad); *broad = NULL; + assert(RB_FIRST(&epg_serieslinks) == NULL); + assert(RB_FIRST(&epg_episodelinks) == NULL); } diff --git a/src/epg.h b/src/epg.h index 294812cae..fc4ec0e99 100644 --- a/src/epg.h +++ b/src/epg.h @@ -40,6 +40,7 @@ typedef LIST_HEAD(,epg_object) epg_object_list_t; typedef RB_HEAD (,epg_object) epg_object_tree_t; typedef LIST_HEAD(,epg_broadcast) epg_broadcast_list_t; typedef RB_HEAD (,epg_broadcast) epg_broadcast_tree_t; +typedef RB_HEAD (,epg_set) epg_set_tree_t; typedef LIST_HEAD(,epg_genre) epg_genre_list_t; /* @@ -48,8 +49,12 @@ typedef LIST_HEAD(,epg_genre) epg_genre_list_t; typedef struct epg_genre epg_genre_t; typedef struct epg_object epg_object_t; typedef struct epg_broadcast epg_broadcast_t; +typedef struct epg_set_item epg_set_item_t; +typedef struct epg_set epg_set_t; extern int epg_in_load; +extern epg_set_tree_t epg_episodelinks; +extern epg_set_tree_t epg_serieslinks; /* * @@ -155,7 +160,6 @@ typedef struct epg_object_ops { /* Object */ struct epg_object { - RB_ENTRY(epg_object) uri_link; ///< Global URI link RB_ENTRY(epg_object) id_link; ///< Global (ID) link LIST_ENTRY(epg_object) un_link; ///< Global unref'd link LIST_ENTRY(epg_object) up_link; ///< Global updated link @@ -217,6 +221,28 @@ int epg_episode_number_cmp int epg_episode_number_cmpfull ( const epg_episode_num_t *a, const epg_episode_num_t *b ); +/* ************************************************************************ + * Broadcast set + * ***********************************************************************/ + +struct epg_set_item { + LIST_ENTRY(epg_set_item) item_link; + epg_broadcast_t *broadcast; +}; + +struct epg_set { + RB_ENTRY(epg_set) set_link; + LIST_HEAD(, epg_set_item) broadcasts; + char uri[0]; +}; + +epg_set_t *epg_set_broadcast_insert + (epg_set_tree_t *tree, epg_broadcast_t *b, const char *uri); +void epg_set_broadcast_remove + (epg_set_tree_t *tree, epg_set_t *set, epg_broadcast_t *b); +epg_set_t *epg_set_broadcast_find_by_uri + (epg_set_tree_t *tree, const char *uri); + /* ************************************************************************ * Broadcast - specific airing (channel & time) of an episode * ***********************************************************************/ @@ -263,7 +289,7 @@ struct epg_broadcast char *image; ///< Episode image epg_genre_list_t genre; ///< Episode genre(s) - epg_episode_num_t epnum; ///< Episode numbering + epg_episode_num_t epnum; ///< Episode numbering; NOTE: use the accessor routine! htsmsg_t *credits; ///< Cast/Credits map of name -> role type (actor, presenter, director, etc). lang_str_t *credits_cached; ///< Comma separated cast (for regex searching in GUI/autorec). Kept in sync with cast_map @@ -272,17 +298,15 @@ struct epg_broadcast ///< Used with drop-down lists in the GUI. string_list_t *keyword; ///< Extra keywords (typically from xmltv) such as "Wild West" or "Unicorn". lang_str_t *keyword_cached; ///< Cached CSV version for regex searches. - char *serieslink_uri; ///< SeriesLink URI - char *episode_uri; ///< Episode URI - - // Note: do not use epnum directly! use the accessor routine - - time_t first_aired; ///< Original airdate - uint16_t copyright_year; ///< xmltv DTD gives a tag "date" (separate to previously-shown/first aired). - ///< This is the date programme was "finished...probably the copyright date." - ///< We'll call it copyright_year since words like "complete" and "finished" - ///< sound too similar to dvr recorded functionality. We'll only store the - ///< year since we only get year not month and day. + epg_set_t *serieslink; ///< Series Link + epg_set_t *episodelink; ///< Episode Link + + time_t first_aired; ///< Original airdate + uint16_t copyright_year; ///< xmltv DTD gives a tag "date" (separate to previously-shown/first aired). + ///< This is the date programme was "finished...probably the copyright date." + ///< We'll call it copyright_year since words like "complete" and "finished" + ///< sound too similar to dvr recorded functionality. We'll only store the + ///< year since we only get year not month and day. }; /* Lookup */ @@ -358,7 +382,7 @@ int epg_broadcast_set_keyword int epg_broadcast_set_serieslink_uri ( epg_broadcast_t *b, const char *uri, epg_changes_t *changed ) __attribute__((warn_unused_result)); -int epg_broadcast_set_episode_uri +int epg_broadcast_set_episodelink_uri ( epg_broadcast_t *b, const char *uri, epg_changes_t *changed ) __attribute__((warn_unused_result)); int epg_broadcast_set_epnumber @@ -421,7 +445,7 @@ size_t epg_broadcast_epnumber_format static inline int epg_episode_match(epg_broadcast_t *a, epg_broadcast_t *b) { if (a == NULL || b == NULL) return 0; - return strcmp(a->episode_uri ?: "", b->episode_uri ?: "") == 0; + return a->episodelink == b->episodelink; } /* Serialization */ diff --git a/src/epgdb.c b/src/epgdb.c index 9f91d140b..d60848af3 100644 --- a/src/epgdb.c +++ b/src/epgdb.c @@ -90,8 +90,6 @@ static void epg_memoryinfo_broadcasts_update(memoryinfo_t *my) size += sizeof(*ebc); size += tvh_strlen(ebc->image); size += tvh_strlen(ebc->epnum.text); - size += tvh_strlen(ebc->episode_uri); - size += tvh_strlen(ebc->serieslink_uri); size += lang_str_size(ebc->title); size += lang_str_size(ebc->subtitle); size += lang_str_size(ebc->summary); diff --git a/src/epggrab/module/eit.c b/src/epggrab/module/eit.c index a1dc23c26..410e1f6d3 100644 --- a/src/epggrab/module/eit.c +++ b/src/epggrab/module/eit.c @@ -610,7 +610,6 @@ static int _eit_process_event_one uint8_t running; epg_broadcast_t *ebc, _ebc; epg_running_t run; - lang_str_t *title_copy = NULL; epg_changes_t changes = 0; char tm1[32], tm2[32]; int short_target = ((eit_module_t *)mod)->short_target; @@ -646,12 +645,12 @@ static int _eit_process_event_one _ebc.dvb_eid = eid; _ebc.start = start; _ebc.stop = stop; - _ebc.episode_uri = ev->uri; - _ebc.serieslink_uri = ev->suri; - _ebc.title = title_copy = lang_str_copy(ev->title); - + _ebc.episodelink = epg_set_broadcast_find_by_uri(&epg_episodelinks, ev->uri); + _ebc.serieslink = epg_set_broadcast_find_by_uri(&epg_serieslinks, ev->suri); + _ebc.title = lang_str_copy(ev->title); ebc = epg_match_now_next(ch, &_ebc); tvhtrace(mod->subsys, "%s: running state only ebc=%p", svc->s_dvb_svcname ?: "(null)", ebc); + lang_str_destroy(_ebc.title); goto running; } else { *save = save2; @@ -691,7 +690,7 @@ static int _eit_process_event_one /* Find episode */ if (*ev->uri) - *save |= epg_broadcast_set_episode_uri(ebc, ev->suri, &changes); + *save |= epg_broadcast_set_episodelink_uri(ebc, ev->suri, &changes); /* Update Episode */ if (ev->is_new > 0) @@ -737,7 +736,6 @@ running: } } - if (title_copy) lang_str_destroy(title_copy); return 0; } diff --git a/src/epggrab/module/xmltv.c b/src/epggrab/module/xmltv.c index accd4e474..825807bc1 100644 --- a/src/epggrab/module/xmltv.c +++ b/src/epggrab/module/xmltv.c @@ -613,9 +613,8 @@ static int _xmltv_parse_programme_tags epg_broadcast_t *ebc; epg_genre_list_t *egl; epg_episode_num_t epnum; - memset(&epnum, 0, sizeof(epnum)); + epg_set_t *set; char *suri = NULL, *uri = NULL; - const char *s; lang_str_t *title = NULL; lang_str_t *desc = NULL; lang_str_t *summary = NULL; @@ -623,6 +622,8 @@ static int _xmltv_parse_programme_tags time_t first_aired = 0; int8_t bw = -1; + memset(&epnum, 0, sizeof(epnum)); + /* * Broadcast */ @@ -716,12 +717,12 @@ static int _xmltv_parse_programme_tags * Series Link */ if (suri) { - s = ebc->serieslink_uri; + set = ebc->serieslink; save |= epg_broadcast_set_serieslink_uri(ebc, suri, &changes); free(suri); stats->seasons.total++; if (changes & EPG_CHANGED_SERIESLINK) { - if (s == NULL) + if (set == NULL) stats->seasons.created++; else stats->seasons.modified++; @@ -732,11 +733,11 @@ static int _xmltv_parse_programme_tags * Episode */ if (uri) { - s = ebc->episode_uri; - save |= epg_broadcast_set_episode_uri(ebc, uri, &changes); + set = ebc->episodelink; + save |= epg_broadcast_set_episodelink_uri(ebc, uri, &changes); stats->episodes.total++; if (changes & EPG_CHANGED_EPISODE) { - if (s == NULL) + if (set == NULL) stats->episodes.created++; else stats->episodes.modified++; diff --git a/src/htsp_server.c b/src/htsp_server.c index 291f2e16c..e723d00b7 100644 --- a/src/htsp_server.c +++ b/src/htsp_server.c @@ -1287,12 +1287,12 @@ htsp_build_event htsmsg_add_msg(out, "keyword", string_list_to_htsmsg(e->keyword)); } - if (e->serieslink_uri) - htsmsg_add_str(out, "serieslinkUri", e->serieslink_uri); + if (e->serieslink) + htsmsg_add_str(out, "serieslinkUri", e->serieslink->uri); /* tvh:// uris are internal */ - if (e->episode_uri && strncasecmp(e->episode_uri, "tvh://", 6)) - htsmsg_add_str(out, "episodeUri", e->episode_uri); + if (e->episodelink && strncasecmp(e->episodelink->uri, "tvh://", 6)) + htsmsg_add_str(out, "episodeUri", e->episodelink->uri); if((g = LIST_FIRST(&e->genre))) { uint32_t code = g->code;