From 02392262085e51aaf7b8fa2e1751c349bf84c86c Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 1 Feb 2016 21:39:50 +0100 Subject: [PATCH] epg: move from 'merge' to 'complete update' behaviour --- src/dvr/dvr_autorec.c | 6 +- src/epg.c | 702 ++++++++++++++++++++++-------------- src/epg.h | 180 +++++---- src/epggrab/module/eit.c | 67 ++-- src/epggrab/module/opentv.c | 51 ++- src/epggrab/module/psip.c | 31 +- src/epggrab/module/pyepg.c | 115 +++--- src/epggrab/module/xmltv.c | 95 ++--- src/epggrab/private.h | 4 +- src/lang_str.c | 14 +- src/lang_str.h | 7 +- 11 files changed, 778 insertions(+), 494 deletions(-) diff --git a/src/dvr/dvr_autorec.c b/src/dvr/dvr_autorec.c index 2e222f27d..368a7477e 100644 --- a/src/dvr/dvr_autorec.c +++ b/src/dvr/dvr_autorec.c @@ -813,7 +813,7 @@ dvr_autorec_entry_class_brand_set(void *o, const void *v) if (v && *(char *)v == '\0') v = NULL; - brand = v ? epg_brand_find_by_uri(v, 1, &save) : NULL; + brand = v ? epg_brand_find_by_uri(v, NULL, 1, &save, NULL) : NULL; if (brand && dae->dae_brand != brand) { if (dae->dae_brand) dae->dae_brand->putref((epg_object_t*)dae->dae_brand); @@ -849,7 +849,7 @@ dvr_autorec_entry_class_season_set(void *o, const void *v) if (v && *(char *)v == '\0') v = NULL; - season = v ? epg_season_find_by_uri(v, 1, &save) : NULL; + season = v ? epg_season_find_by_uri(v, NULL, 1, &save, NULL) : NULL; if (season && dae->dae_season != season) { if (dae->dae_season) dae->dae_season->putref((epg_object_t*)dae->dae_season); @@ -885,7 +885,7 @@ dvr_autorec_entry_class_series_link_set(void *o, const void *v) if (v && *(char *)v == '\0') v = NULL; - sl = v ? epg_serieslink_find_by_uri(v, 1, &save) : NULL; + sl = v ? epg_serieslink_find_by_uri(v, NULL, 1, &save, NULL) : NULL; if (sl && dae->dae_serieslink != sl) { if (dae->dae_serieslink) dae->dae_serieslink->putref((epg_object_t*)dae->dae_season); diff --git a/src/epg.c b/src/epg.c index 9f6a57e4f..de01e7e62 100644 --- a/src/epg.c +++ b/src/epg.c @@ -186,6 +186,18 @@ static void _epg_object_set_updated ( void *o ) } } +static int _epg_object_set_grabber ( void *o, epggrab_module_t *grab ) +{ + epg_object_t *eo = o; + if (!grab) return 1; // grab=NULL is override + if (!eo->grabber || + ((eo->grabber != grab) && (grab->priority > eo->grabber->priority))) { + eo->grabber = grab; + return 1; + } + return grab == eo->grabber; +} + static void _epg_object_create ( void *o ) { epg_object_t *eo = o; @@ -211,10 +223,11 @@ static void _epg_object_create ( void *o ) } static epg_object_t *_epg_object_find_by_uri - ( const char *uri, int create, int *save, - epg_object_tree_t *tree, epg_object_t **skel ) + ( const char *uri, epggrab_module_t *src, int create, int *save, + uint32_t *changes, epg_object_tree_t *tree, epg_object_t **skel ) { epg_object_t *eo; + int _save; assert(skel != NULL); lock_assert(&global_lock); @@ -229,6 +242,7 @@ static epg_object_t *_epg_object_find_by_uri } else { eo = RB_INSERT_SORTED(tree, *skel, uri_link, _uri_cmp); if (!eo) { + if (changes) *changes |= EPG_CHANGED_CREATE; *save = 1; eo = *skel; *skel = NULL; @@ -236,6 +250,10 @@ static epg_object_t *_epg_object_find_by_uri _epg_object_create(eo); } } + if (eo) { + _save = _epg_object_set_grabber(eo, src); + if (save) *save |= _save; + } return eo; } @@ -287,27 +305,17 @@ static epg_object_t *_epg_object_deserialize ( htsmsg_t *m, epg_object_t *eo ) return eo; } -static int _epg_object_set_grabber ( void *o, epggrab_module_t *grab ) -{ - epg_object_t *eo = o; - if (!grab) return 1; // grab=NULL is override - if (!eo->grabber || - ((eo->grabber != grab) && (grab->priority > eo->grabber->priority))) { - eo->grabber = grab; - return 2; - } - return grab == eo->grabber; -} - static int _epg_object_set_str - ( void *o, char **old, const char *newstr, epggrab_module_t *src ) + ( void *o, char **old, const char *newstr, + uint32_t *changed, uint32_t cflag ) { int save = 0; epg_object_t *eo = o; - if (!eo || !_epg_object_set_grabber(eo, src)) return 0; + if (!eo) return 0; + if (changed) *changed |= cflag; if (!*old && !newstr) return 0; if (!*old || !newstr || strcmp(*old, newstr)) { - if (*old) free(*old); + free(*old); *old = newstr ? strdup(newstr) : NULL; _epg_object_set_updated(eo); save = 1; @@ -316,43 +324,35 @@ static int _epg_object_set_str } static int _epg_object_set_lang_str - ( void *o, lang_str_t **old, const char *newstr, const char *newlang, - epggrab_module_t *src ) + ( void *o, lang_str_t **old, const lang_str_t *str, + uint32_t *changed, uint32_t cflag ) { - int save, nflag; - epg_object_t *eo = o; - nflag = _epg_object_set_grabber(eo, src); - if (!eo || !nflag) return 0; - if (nflag == 2) { /* changed grabber */ + if (!o) return 0; + if (changed) *changed |= cflag; + if (!*old) { + if (!str) + return 0; + } + if (!str) { lang_str_destroy(*old); *old = NULL; + return 1; } - if (!*old) { - if (!newstr) - return 0; - *old = lang_str_create(); + if (lang_str_compare(*old, str)) { + lang_str_destroy(*old); + *old = lang_str_copy(str); + return 1; } - save = lang_str_add(*old, newstr, newlang, 1); - if (save) - _epg_object_set_updated(eo); - return save; -} - -static int _epg_object_set_lang_str2 - ( void *o, lang_str_t **old, const lang_str_t *str, epggrab_module_t *src ) -{ - int save = 0; - lang_str_ele_t *ls; - RB_FOREACH(ls, str, link) - save |= _epg_object_set_lang_str(o, old, ls->str, ls->lang, src); - return save; + return 0; } static int _epg_object_set_u8 - ( void *o, uint8_t *old, const uint8_t nval, epggrab_module_t *src ) + ( void *o, uint8_t *old, const uint8_t nval, + uint32_t *changed, uint32_t cflag ) { int save; - if (!o || !_epg_object_set_grabber(o, src)) return 0; + if (!o) return 0; + if (changed) *changed |= cflag; if ((save = (*old != nval)) != 0) { *old = nval; _epg_object_set_updated(o); @@ -361,10 +361,12 @@ static int _epg_object_set_u8 } static int _epg_object_set_u16 - ( void *o, uint16_t *old, const uint16_t nval, epggrab_module_t *src ) + ( void *o, uint16_t *old, const uint16_t nval, + uint32_t *changed, uint32_t cflag ) { int save = 0; - if (!o || !_epg_object_set_grabber(o, src)) return 0; + if (!o) return 0; + if (changed) *changed |= cflag; if ((save = (*old != nval)) != 0) { *old = nval; _epg_object_set_updated(o); @@ -452,10 +454,11 @@ static epg_object_t **_epg_brand_skel ( void ) } epg_brand_t* epg_brand_find_by_uri - ( const char *uri, int create, int *save ) + ( const char *uri, epggrab_module_t *src, + int create, int *save, uint32_t *changed ) { return (epg_brand_t*) - _epg_object_find_by_uri(uri, create, save, + _epg_object_find_by_uri(uri, src, create, save, changed, &epg_brands, _epg_brand_skel()); } @@ -465,38 +468,57 @@ epg_brand_t *epg_brand_find_by_id ( uint32_t id ) return (epg_brand_t*)epg_object_find_by_id(id, EPG_BRAND); } +int epg_brand_change_finish + ( epg_brand_t *brand, uint32_t changes, int merge ) +{ + int save = 0; + if (merge) return 0; + if (changes & EPG_CHANGED_CREATE) return 0; + if (!(changes & EPG_CHANGED_TITLE)) + save |= epg_brand_set_title(brand, NULL, NULL); + if (!(changes & EPG_CHANGED_SUMMARY)) + save |= epg_brand_set_summary(brand, NULL, NULL); + if (!(changes & EPG_CHANGED_IMAGE)) + save |= epg_brand_set_image(brand, NULL, NULL); + if (!(changes & EPG_CHANGED_SEASON_COUNT)) + save |= epg_brand_set_season_count(brand, 0, NULL); + return save; +} + int epg_brand_set_title - ( epg_brand_t *brand, const char *title, const char *lang, - epggrab_module_t *src ) + ( epg_brand_t *brand, const lang_str_t *title, uint32_t *changed ) { if (!brand) return 0; - return _epg_object_set_lang_str(brand, &brand->title, title, lang, src); + return _epg_object_set_lang_str(brand, &brand->title, title, + changed, EPG_CHANGED_TITLE); } int epg_brand_set_summary - ( epg_brand_t *brand, const char *summary, const char *lang, - epggrab_module_t *src ) + ( epg_brand_t *brand, const lang_str_t *summary, uint32_t *changed ) { if (!brand) return 0; - return _epg_object_set_lang_str(brand, &brand->summary, summary, lang, src); + return _epg_object_set_lang_str(brand, &brand->summary, summary, + changed, EPG_CHANGED_SUMMARY); } int epg_brand_set_image - ( epg_brand_t *brand, const char *image, epggrab_module_t *src ) + ( epg_brand_t *brand, const char *image, uint32_t *changed ) { int save; if (!brand) return 0; - save = _epg_object_set_str(brand, &brand->image, image, src); + save = _epg_object_set_str(brand, &brand->image, image, + changed, EPG_CHANGED_IMAGE); if (save) imagecache_get_id(image); return save; } int epg_brand_set_season_count - ( epg_brand_t *brand, uint16_t count, epggrab_module_t *src ) + ( epg_brand_t *brand, uint16_t count, uint32_t *changed ) { if (!brand) return 0; - return _epg_object_set_u16(brand, &brand->season_count, count, src); + return _epg_object_set_u16(brand, &brand->season_count, count, + changed, EPG_CHANGED_SEASON_COUNT); } static void _epg_brand_add_season @@ -551,29 +573,29 @@ epg_brand_t *epg_brand_deserialize ( htsmsg_t *m, int create, int *save ) { epg_object_t **skel = _epg_brand_skel(); epg_brand_t *eb; - uint32_t u32; + uint32_t u32, changes = 0; const char *str; lang_str_t *ls; - lang_str_ele_t *e; if (!_epg_object_deserialize(m, *skel)) return NULL; - if (!(eb = epg_brand_find_by_uri((*skel)->uri, create, save))) return NULL; + if (!(eb = epg_brand_find_by_uri((*skel)->uri, (*skel)->grabber, + create, save, &changes))) + return NULL; if ((ls = lang_str_deserialize(m, "title"))) { - RB_FOREACH(e, ls, link) - *save |= epg_brand_set_title(eb, e->str, e->lang, NULL); + *save |= epg_brand_set_title(eb, ls, &changes); lang_str_destroy(ls); } if ((ls = lang_str_deserialize(m, "summary"))) { - RB_FOREACH(e, ls, link) - *save |= epg_brand_set_summary(eb, e->str, e->lang, NULL); + *save |= epg_brand_set_summary(eb, ls, &changes); lang_str_destroy(ls); } - if ( !htsmsg_get_u32(m, "season-count", &u32) ) + if (!htsmsg_get_u32(m, "season-count", &u32)) *save |= epg_brand_set_season_count(eb, u32, NULL); + if ((str = htsmsg_get_str(m, "image"))) + *save |= epg_brand_set_image(eb, str, &changes); - if ( (str = htsmsg_get_str(m, "image")) ) - *save |= epg_brand_set_image(eb, str, NULL); + *save |= epg_brand_change_finish(eb, changes, 0); return eb; } @@ -639,10 +661,11 @@ static epg_object_t **_epg_season_skel ( void ) } epg_season_t* epg_season_find_by_uri - ( const char *uri, int create, int *save ) + ( const char *uri, epggrab_module_t *src, + int create, int *save, uint32_t *changed ) { return (epg_season_t*) - _epg_object_find_by_uri(uri, create, save, + _epg_object_find_by_uri(uri, src, create, save, changed, &epg_seasons, _epg_season_skel()); } @@ -652,44 +675,67 @@ epg_season_t *epg_season_find_by_id ( uint32_t id ) return (epg_season_t*)epg_object_find_by_id(id, EPG_SEASON); } +int epg_season_change_finish + ( epg_season_t *season, uint32_t changes, int merge ) +{ + int save = 0; + if (merge) return 0; + if (changes & EPG_CHANGED_CREATE) return 0; + if (!(changes & EPG_CHANGED_SUMMARY)) + save |= epg_season_set_summary(season, NULL, NULL); + if (!(changes & EPG_CHANGED_IMAGE)) + save |= epg_season_set_image(season, NULL, NULL); + if (!(changes & EPG_CHANGED_EPISODE_COUNT)) + save |= epg_season_set_episode_count(season, 0, NULL); + if (!(changes & EPG_CHANGED_SEASON_NUMBER)) + save |= epg_season_set_number(season, 0, NULL); + if (!(changes & EPG_CHANGED_BRAND)) + save |= epg_season_set_brand(season, 0, NULL); + return save; +} + int epg_season_set_summary - ( epg_season_t *season, const char *summary, const char *lang, - epggrab_module_t *src ) + ( epg_season_t *season, const lang_str_t *summary, uint32_t *changed ) { if (!season) return 0; - return _epg_object_set_lang_str(season, &season->summary, summary, lang, src); + return _epg_object_set_lang_str(season, &season->summary, summary, + changed, EPG_CHANGED_SUMMARY); } int epg_season_set_image - ( epg_season_t *season, const char *image, epggrab_module_t *src ) + ( epg_season_t *season, const char *image, uint32_t *changed ) { int save; if (!season) return 0; - save = _epg_object_set_str(season, &season->image, image, src); + save = _epg_object_set_str(season, &season->image, image, + changed, EPG_CHANGED_IMAGE); if (save) imagecache_get_id(image); return save; } int epg_season_set_episode_count - ( epg_season_t *season, uint16_t count, epggrab_module_t *src ) + ( epg_season_t *season, uint16_t count, uint32_t *changed ) { if (!season) return 0; - return _epg_object_set_u16(season, &season->episode_count, count, src); + return _epg_object_set_u16(season, &season->episode_count, count, + changed, EPG_CHANGED_EPISODE_COUNT); } int epg_season_set_number - ( epg_season_t *season, uint16_t number, epggrab_module_t *src ) + ( epg_season_t *season, uint16_t number, uint32_t *changed ) { if (!season) return 0; - return _epg_object_set_u16(season, &season->number, number, src); + return _epg_object_set_u16(season, &season->number, number, + changed, EPG_CHANGED_SEASON_NUMBER); } int epg_season_set_brand - ( epg_season_t *season, epg_brand_t *brand, epggrab_module_t *src ) + ( epg_season_t *season, epg_brand_t *brand, uint32_t *changed ) { int save = 0; - if (!season || !_epg_object_set_grabber(season, src)) return 0; + if (!season) return 0; + if (changed) *changed |= EPG_CHANGED_BRAND; if (season->brand != brand) { if (season->brand) _epg_brand_rem_season(season->brand, season); season->brand = brand; @@ -739,30 +785,33 @@ epg_season_t *epg_season_deserialize ( htsmsg_t *m, int create, int *save ) epg_object_t **skel = _epg_season_skel(); epg_season_t *es; epg_brand_t *eb; - uint32_t u32; + uint32_t u32, changes = 0; const char *str; lang_str_t *ls; - lang_str_ele_t *e; if (!_epg_object_deserialize(m, *skel)) return NULL; - if (!(es = epg_season_find_by_uri((*skel)->uri, create, save))) return NULL; + if (!(es = epg_season_find_by_uri((*skel)->uri, (*skel)->grabber, + create, save, &changes))) + return NULL; if ((ls = lang_str_deserialize(m, "summary"))) { - RB_FOREACH(e, ls, link) - *save |= epg_season_set_summary(es, e->str, e->lang, NULL); + *save |= epg_season_set_summary(es, ls, &changes); lang_str_destroy(ls); } + if (!htsmsg_get_u32(m, "number", &u32)) - *save |= epg_season_set_number(es, u32, NULL); + *save |= epg_season_set_number(es, u32, &changes); if (!htsmsg_get_u32(m, "episode-count", &u32)) - *save |= epg_season_set_episode_count(es, u32, NULL); + *save |= epg_season_set_episode_count(es, u32, &changes); if ((str = htsmsg_get_str(m, "brand"))) - if ( (eb = epg_brand_find_by_uri(str, 0, NULL))) - *save |= epg_season_set_brand(es, eb, NULL); + if ((eb = epg_brand_find_by_uri(str, es->grabber, 0, NULL, NULL))) + *save |= epg_season_set_brand(es, eb, &changes); if ((str = htsmsg_get_str(m, "image"))) - *save |= epg_season_set_image(es, str, NULL); + *save |= epg_season_set_image(es, str, &changes); + + *save |= epg_season_change_finish(es, changes, 0); return es; } @@ -866,10 +915,11 @@ static epg_object_t **_epg_episode_skel ( void ) } epg_episode_t* epg_episode_find_by_uri - ( const char *uri, int create, int *save ) + ( const char *uri, epggrab_module_t *src, int create, + int *save, uint32_t *changed ) { return (epg_episode_t*) - _epg_object_find_by_uri(uri, create, save, + _epg_object_find_by_uri(uri, src, create, save, changed, &epg_episodes, _epg_episode_skel()); } @@ -879,86 +929,136 @@ epg_episode_t *epg_episode_find_by_id ( uint32_t id ) return (epg_episode_t*)epg_object_find_by_id(id, EPG_EPISODE); } -int epg_episode_set_title - ( epg_episode_t *episode, const char *title, const char *lang, - epggrab_module_t *src ) +epg_episode_t *epg_episode_find_by_broadcast + ( epg_broadcast_t *ebc, epggrab_module_t *src, + int create, int *save, uint32_t *changed ) { - if (!episode) return 0; - return _epg_object_set_lang_str(episode, &episode->title, title, lang, src); + char uri[UUID_HEX_SIZE+50], ubuf[UUID_HEX_SIZE]; + if (!ebc) return NULL; + if (ebc->episode) { + _epg_object_set_grabber(ebc->episode, src); + return ebc->episode; + } + if (!create) return NULL; + snprintf(uri, sizeof(uri)-1, "tvh://channel-%s/bcast-%u/episode", + idnode_uuid_as_str(&ebc->channel->ch_id, ubuf), ebc->id); + return epg_episode_find_by_uri(uri, src, 1, save, changed); } -int epg_episode_set_title2 - ( epg_episode_t *episode, const lang_str_t *str, epggrab_module_t *src ) +int epg_episode_change_finish + ( epg_episode_t *episode, uint32_t changes, int merge ) { - if (!episode) return 0; - return _epg_object_set_lang_str2(episode, &episode->title, str, src); + int save = 0; + if (merge) return 0; + if (changes & EPG_CHANGED_CREATE) return 0; + if (!(changes & EPG_CHANGED_TITLE)) + save |= epg_episode_set_title(episode, NULL, NULL); + if (!(changes & EPG_CHANGED_SUBTITLE)) + save |= epg_episode_set_subtitle(episode, NULL, NULL); + if (!(changes & EPG_CHANGED_SUMMARY)) + save |= epg_episode_set_summary(episode, NULL, NULL); + if (!(changes & EPG_CHANGED_DESCRIPTION)) + save |= epg_episode_set_description(episode, NULL, NULL); + if (!(changes & EPG_CHANGED_IMAGE)) + save |= epg_episode_set_image(episode, NULL, NULL); + if (!(changes & EPG_CHANGED_EPSER_NUM)) + save |= _epg_object_set_u16(episode, &episode->epnum.s_num, 0, NULL, 0); + if (!(changes & EPG_CHANGED_EPSER_CNT)) + save |= _epg_object_set_u16(episode, &episode->epnum.s_cnt, 0, NULL, 0); + if (!(changes & EPG_CHANGED_EPNUM_NUM)) + save |= _epg_object_set_u16(episode, &episode->epnum.e_num, 0, NULL, 0); + if (!(changes & EPG_CHANGED_EPNUM_CNT)) + save |= _epg_object_set_u16(episode, &episode->epnum.e_cnt, 0, NULL, 0); + if (!(changes & EPG_CHANGED_EPPAR_NUM)) + save |= _epg_object_set_u16(episode, &episode->epnum.p_num, 0, NULL, 0); + if (!(changes & EPG_CHANGED_EPPAR_CNT)) + save |= _epg_object_set_u16(episode, &episode->epnum.p_cnt, 0, NULL, 0); + if (!(changes & EPG_CHANGED_EPTEXT)) + save |= _epg_object_set_str(episode, &episode->epnum.text, NULL, NULL, 0); + if (!(changes & EPG_CHANGED_BRAND)) + save |= epg_episode_set_brand(episode, NULL, NULL); + if (!(changes & EPG_CHANGED_SEASON)) + save |= epg_episode_set_brand(episode, NULL, NULL); + if (!(changes & EPG_CHANGED_GENRE)) + save |= epg_episode_set_genre(episode, NULL, NULL); + if (!(changes & EPG_CHANGED_IS_BW)) + save |= epg_episode_set_is_bw(episode, 0, NULL); + if (!(changes & EPG_CHANGED_STAR_RATING)) + save |= epg_episode_set_star_rating(episode, 0, NULL); + if (!(changes & EPG_CHANGED_AGE_RATING)) + save |= epg_episode_set_age_rating(episode, 0, NULL); + if (!(changes & EPG_CHANGED_FIRST_AIRED)) + save |= epg_episode_set_first_aired(episode, 0, NULL); + return save; } -int epg_episode_set_subtitle - ( epg_episode_t *episode, const char *subtitle, const char *lang, - epggrab_module_t *src ) +int epg_episode_set_title + ( epg_episode_t *episode, const lang_str_t *title, uint32_t *changed ) { if (!episode) return 0; - return _epg_object_set_lang_str(episode, &episode->subtitle, - subtitle, lang, src); + return _epg_object_set_lang_str(episode, &episode->title, title, + changed, EPG_CHANGED_TITLE); } -int epg_episode_set_subtitle2 - ( epg_episode_t *episode, const lang_str_t *str, epggrab_module_t *src ) +int epg_episode_set_subtitle + ( epg_episode_t *episode, const lang_str_t *subtitle, uint32_t *changed ) { if (!episode) return 0; - return _epg_object_set_lang_str2(episode, &episode->subtitle, str, src); + return _epg_object_set_lang_str(episode, &episode->subtitle, + subtitle, changed, EPG_CHANGED_SUBTITLE); } int epg_episode_set_summary - ( epg_episode_t *episode, const char *summary, const char *lang, - epggrab_module_t *src ) + ( epg_episode_t *episode, const lang_str_t *summary, uint32_t *changed ) { if (!episode) return 0; return _epg_object_set_lang_str(episode, &episode->summary, - summary, lang, src); + summary, changed, EPG_CHANGED_SUMMARY); } int epg_episode_set_description - ( epg_episode_t *episode, const char *desc, const char *lang, - epggrab_module_t *src ) + ( epg_episode_t *episode, const lang_str_t *desc, uint32_t *changed ) { if (!episode) return 0; return _epg_object_set_lang_str(episode, &episode->description, - desc, lang, src); + desc, changed, EPG_CHANGED_DESCRIPTION); } int epg_episode_set_image - ( epg_episode_t *episode, const char *image, epggrab_module_t *src ) + ( epg_episode_t *episode, const char *image, uint32_t *changed ) { int save; if (!episode) return 0; - save = _epg_object_set_str(episode, &episode->image, image, src); + save = _epg_object_set_str(episode, &episode->image, image, + changed, EPG_CHANGED_IMAGE); if (save) imagecache_get_id(image); return save; } int epg_episode_set_number - ( epg_episode_t *episode, uint16_t number, epggrab_module_t *src ) + ( epg_episode_t *episode, uint16_t number, uint32_t *changed ) { if (!episode) return 0; - return _epg_object_set_u16(episode, &episode->epnum.e_num, number, src); + return _epg_object_set_u16(episode, &episode->epnum.e_num, number, + changed, EPG_CHANGED_EPNUM_NUM); } int epg_episode_set_part ( epg_episode_t *episode, uint16_t part, uint16_t count, - epggrab_module_t *src ) + uint32_t *changed ) { int save = 0; if (!episode) return 0; - save |= _epg_object_set_u16(episode, &episode->epnum.p_num, part, src); - save |= _epg_object_set_u16(episode, &episode->epnum.p_cnt, count, src); + save |= _epg_object_set_u16(episode, &episode->epnum.p_num, part, + changed, EPG_CHANGED_EPPAR_NUM); + save |= _epg_object_set_u16(episode, &episode->epnum.p_cnt, count, + changed, EPG_CHANGED_EPPAR_CNT); return save; } int epg_episode_set_epnum - ( epg_episode_t *episode, epg_episode_num_t *num, epggrab_module_t *src ) + ( epg_episode_t *episode, epg_episode_num_t *num, uint32_t *changed ) { int save = 0; static epg_episode_num_t _zero = { 0 }; @@ -968,33 +1068,34 @@ int epg_episode_set_epnum num = &_zero; if (num->s_num) save |= _epg_object_set_u16(episode, &episode->epnum.s_num, - num->s_num, src); + num->s_num, changed, EPG_CHANGED_EPSER_NUM); if (num->s_cnt) save |= _epg_object_set_u16(episode, &episode->epnum.s_cnt, - num->s_cnt, src); + num->s_cnt, changed, EPG_CHANGED_EPSER_CNT); if (num->e_num) save |= _epg_object_set_u16(episode, &episode->epnum.e_num, - num->e_num, src); + num->e_num, changed, EPG_CHANGED_EPNUM_NUM); if (num->e_cnt) save |= _epg_object_set_u16(episode, &episode->epnum.e_cnt, - num->e_cnt, src); + num->e_cnt, changed, EPG_CHANGED_EPNUM_CNT); if (num->p_num) save |= _epg_object_set_u16(episode, &episode->epnum.p_num, - num->p_num, src); + num->p_num, changed, EPG_CHANGED_EPPAR_NUM); if (num->p_cnt) save |= _epg_object_set_u16(episode, &episode->epnum.p_cnt, - num->p_cnt, src); + num->p_cnt, changed, EPG_CHANGED_EPPAR_CNT); if (num->text) save |= _epg_object_set_str(episode, &episode->epnum.text, - num->text, src); + num->text, changed, EPG_CHANGED_EPTEXT); return save; } int epg_episode_set_brand - ( epg_episode_t *episode, epg_brand_t *brand, epggrab_module_t *src ) + ( epg_episode_t *episode, epg_brand_t *brand, uint32_t *changed ) { int save = 0; - if (!episode && !_epg_object_set_grabber(episode, src)) return 0; + if (!episode) return 0; + if (changed) *changed |= EPG_CHANGED_BRAND; if (episode->brand != brand) { if (episode->brand) _epg_brand_rem_episode(episode->brand, episode); episode->brand = brand; @@ -1006,18 +1107,19 @@ int epg_episode_set_brand } int epg_episode_set_season - ( epg_episode_t *episode, epg_season_t *season, epggrab_module_t *src ) + ( epg_episode_t *episode, epg_season_t *season, uint32_t *changed ) { int save = 0; - if (!episode || !_epg_object_set_grabber(episode, src)) return 0; + if (!episode) return 0; + if (changed) *changed |= EPG_CHANGED_SEASON; if (episode->season != season) { if (episode->season) _epg_season_rem_episode(episode->season, episode); episode->season = season; if (season) { _epg_season_add_episode(season, episode); - save |= epg_episode_set_brand(episode, season->brand ?: NULL, src); + save |= epg_episode_set_brand(episode, season->brand ?: NULL, changed); } else { - save |= epg_episode_set_brand(episode, NULL, src); + save |= epg_episode_set_brand(episode, NULL, changed); } _epg_object_set_updated(episode); save = 1; @@ -1026,13 +1128,16 @@ int epg_episode_set_season } int epg_episode_set_genre - ( epg_episode_t *ee, epg_genre_list_t *genre, epggrab_module_t *src ) + ( epg_episode_t *ee, epg_genre_list_t *genre, uint32_t *changed ) { int save = 0; epg_genre_t *g1, *g2; + if (!ee) return 0; + + if (changed) *changed |= EPG_CHANGED_GENRE; + g1 = LIST_FIRST(&ee->genre); - if (!_epg_object_set_grabber(ee, src) && g1) return 0; /* Remove old */ while (g1) { @@ -1046,44 +1151,49 @@ int epg_episode_set_genre } /* Insert all entries */ - LIST_FOREACH(g1, genre, link) - save |= epg_genre_list_add(&ee->genre, g1); + if (genre) { + LIST_FOREACH(g1, genre, link) + save |= epg_genre_list_add(&ee->genre, g1); + } return save; } int epg_episode_set_is_bw - ( epg_episode_t *episode, uint8_t bw, epggrab_module_t *src ) + ( epg_episode_t *episode, uint8_t bw, uint32_t *changed ) { if (!episode) return 0; - return _epg_object_set_u8(episode, &episode->is_bw, bw, src); + return _epg_object_set_u8(episode, &episode->is_bw, bw, + changed, EPG_CHANGED_IS_BW); } int epg_episode_set_star_rating - ( epg_episode_t *episode, uint8_t stars, epggrab_module_t *src ) + ( epg_episode_t *episode, uint8_t stars, uint32_t *changed ) { if (!episode) return 0; - return _epg_object_set_u8(episode, &episode->star_rating, stars, src); + return _epg_object_set_u8(episode, &episode->star_rating, stars, + changed, EPG_CHANGED_STAR_RATING); } int epg_episode_set_age_rating - ( epg_episode_t *episode, uint8_t age, epggrab_module_t *src ) + ( epg_episode_t *episode, uint8_t age, uint32_t *changed ) { if (!episode) return 0; - return _epg_object_set_u8(episode, &episode->age_rating, age, src); + return _epg_object_set_u8(episode, &episode->age_rating, age, + changed, EPG_CHANGED_AGE_RATING); } int epg_episode_set_first_aired - ( epg_episode_t *episode, time_t aired, epggrab_module_t *src ) + ( epg_episode_t *episode, time_t aired, uint32_t *changed ) { - int save = 0; - if (!episode || !_epg_object_set_grabber(episode, src)) return 0; + if (!episode) return 0; + if (changed) *changed |= EPG_CHANGED_FIRST_AIRED; if (episode->first_aired != aired) { episode->first_aired = aired; _epg_object_set_updated(episode); - save = 1; + return 1; } - return save; + return 0; } static void _epg_episode_add_broadcast @@ -1218,38 +1328,34 @@ epg_episode_t *epg_episode_deserialize ( htsmsg_t *m, int create, int *save ) epg_episode_num_t num; htsmsg_t *sub; htsmsg_field_t *f; - uint32_t u32; + uint32_t u32, changes = 0; int64_t s64; lang_str_t *ls; - lang_str_ele_t *e; if (!_epg_object_deserialize(m, *skel)) return NULL; - if (!(ee = epg_episode_find_by_uri((*skel)->uri, create, save))) + if (!(ee = epg_episode_find_by_uri((*skel)->uri, (*skel)->grabber, + create, save, &changes))) return NULL; if ((ls = lang_str_deserialize(m, "title"))) { - RB_FOREACH(e, ls, link) - *save |= epg_episode_set_title(ee, e->str, e->lang, NULL); + *save |= epg_episode_set_title(ee, ls, &changes); lang_str_destroy(ls); } if ((ls = lang_str_deserialize(m, "subtitle"))) { - RB_FOREACH(e, ls, link) - *save |= epg_episode_set_subtitle(ee, e->str, e->lang, NULL); + *save |= epg_episode_set_subtitle(ee, ls, &changes); lang_str_destroy(ls); } if ((ls = lang_str_deserialize(m, "summary"))) { - RB_FOREACH(e, ls, link) - *save |= epg_episode_set_summary(ee, e->str, e->lang, NULL); + *save |= epg_episode_set_summary(ee, ls, &changes); lang_str_destroy(ls); } if ((ls = lang_str_deserialize(m, "description"))) { - RB_FOREACH(e, ls, link) - *save |= epg_episode_set_description(ee, e->str, e->lang, NULL); + *save |= epg_episode_set_description(ee, ls, &changes); lang_str_destroy(ls); } if ((sub = htsmsg_get_map(m, "epnum"))) { epg_episode_num_deserialize(sub, &num); - *save |= epg_episode_set_epnum(ee, &num, NULL); + *save |= epg_episode_set_epnum(ee, &num, &changes); if (num.text) free(num.text); } if ((sub = htsmsg_get_list(m, "genre"))) { @@ -1259,31 +1365,33 @@ epg_episode_t *epg_episode_deserialize ( htsmsg_t *m, int create, int *save ) genre.code = (uint8_t)f->hmf_s64; epg_genre_list_add(egl, &genre); } - *save |= epg_episode_set_genre(ee, egl, NULL); + *save |= epg_episode_set_genre(ee, egl, &changes); epg_genre_list_destroy(egl); } if ((str = htsmsg_get_str(m, "season"))) - if ( (es = epg_season_find_by_uri(str, 0, NULL)) ) + if ((es = epg_season_find_by_uri(str, ee->grabber, 0, NULL, &changes))) *save |= epg_episode_set_season(ee, es, NULL); if ((str = htsmsg_get_str(m, "brand"))) - if ((eb = epg_brand_find_by_uri(str, 0, NULL))) + if ((eb = epg_brand_find_by_uri(str, ee->grabber, 0, NULL, &changes))) *save |= epg_episode_set_brand(ee, eb, NULL); if (!htsmsg_get_u32(m, "is_bw", &u32)) - *save |= epg_episode_set_is_bw(ee, u32, NULL); + *save |= epg_episode_set_is_bw(ee, u32, &changes); if (!htsmsg_get_u32(m, "star_rating", &u32)) - *save |= epg_episode_set_star_rating(ee, u32, NULL); + *save |= epg_episode_set_star_rating(ee, u32, &changes); if (!htsmsg_get_u32(m, "age_rating", &u32)) - *save |= epg_episode_set_age_rating(ee, u32, NULL); + *save |= epg_episode_set_age_rating(ee, u32, &changes); if (!htsmsg_get_s64(m, "first_aired", &s64)) - *save |= epg_episode_set_first_aired(ee, (time_t)s64, NULL); + *save |= epg_episode_set_first_aired(ee, (time_t)s64, &changes); if ((str = htsmsg_get_str(m, "image"))) - *save |= epg_episode_set_image(ee, str, NULL); + *save |= epg_episode_set_image(ee, str, &changes); + + *save |= epg_episode_change_finish(ee, changes, 0); return ee; } @@ -1349,10 +1457,11 @@ static epg_object_t **_epg_serieslink_skel ( void ) } epg_serieslink_t* epg_serieslink_find_by_uri - ( const char *uri, int create, int *save ) + ( const char *uri, epggrab_module_t *src, int create, + int *save, uint32_t *changed ) { return (epg_serieslink_t*) - _epg_object_find_by_uri(uri, create, save, + _epg_object_find_by_uri(uri, src, create, save, changed, &epg_serieslinks, _epg_serieslink_skel()); } @@ -1362,6 +1471,12 @@ epg_serieslink_t *epg_serieslink_find_by_id ( uint32_t id ) return (epg_serieslink_t*)epg_object_find_by_id(id, EPG_SERIESLINK); } +int epg_serieslink_change_finish + ( epg_serieslink_t *esl, uint32_t changes, int merge ) +{ + return 0; +} + static void _epg_serieslink_add_broadcast ( epg_serieslink_t *esl, epg_broadcast_t *ebc ) { @@ -1391,10 +1506,14 @@ epg_serieslink_t *epg_serieslink_deserialize { epg_object_t **skel = _epg_serieslink_skel(); epg_serieslink_t *esl; + uint32_t changes = 0; if (!_epg_object_deserialize(m, *skel)) return NULL; - if (!(esl = epg_serieslink_find_by_uri((*skel)->uri, create, save))) + if (!(esl = epg_serieslink_find_by_uri((*skel)->uri, (*skel)->grabber, + create, save, &changes))) return NULL; + + *save |= epg_serieslink_change_finish(esl, changes, 0); return esl; } @@ -1485,8 +1604,8 @@ static void _epg_channel_timer_callback ( void *p ) } static epg_broadcast_t *_epg_channel_add_broadcast - (channel_t *ch, epg_broadcast_t **bcast, epggrab_module_t *src, - int create, int *save) + ( channel_t *ch, epg_broadcast_t **bcast, epggrab_module_t *src, + int create, int *save, uint32_t *changed ) { int timer = 0; epg_broadcast_t *ebc, *ret; @@ -1504,6 +1623,7 @@ static epg_broadcast_t *_epg_channel_add_broadcast /* New */ if (!ret) { + if (changed) *changed |= EPG_CHANGED_CREATE; *save = 1; ret = *bcast; *bcast = NULL; @@ -1519,8 +1639,6 @@ static epg_broadcast_t *_epg_channel_add_broadcast if (!_epg_object_set_grabber(ret, src)) return ret; - *save |= _epg_object_set_u16(ret, &ret->dvb_eid, (*bcast)->dvb_eid, NULL); - /* No time change */ if (ret->stop == (*bcast)->stop) { return ret; @@ -1638,8 +1756,7 @@ static epg_broadcast_t **_epg_broadcast_skel ( void ) epg_broadcast_t *epg_broadcast_find_by_time ( channel_t *channel, epggrab_module_t *src, - time_t start, time_t stop, uint16_t eid, - int create, int *save ) + time_t start, time_t stop, int create, int *save, uint32_t *changed ) { epg_broadcast_t **ebc; if (!channel || !start || !stop) return NULL; @@ -1649,36 +1766,74 @@ epg_broadcast_t *epg_broadcast_find_by_time ebc = _epg_broadcast_skel(); (*ebc)->start = start; (*ebc)->stop = stop; - (*ebc)->dvb_eid = eid; - return _epg_channel_add_broadcast(channel, ebc, src, create, save); + return _epg_channel_add_broadcast(channel, ebc, src, create, save, changed); +} + +int epg_broadcast_change_finish + ( epg_broadcast_t *broadcast, uint32_t changes, int merge ) +{ + int save = 0; + if (merge) return 0; + if (changes & EPG_CHANGED_CREATE) return 0; + if (!(changes & EPG_CHANGED_EPISODE)) + save |= epg_broadcast_set_episode(broadcast, NULL, NULL); + if (!(changes & EPG_CHANGED_SERIESLINK)) + save |= epg_broadcast_set_serieslink(broadcast, NULL, NULL); + if (!(changes & EPG_CHANGED_DVB_EID)) + save |= epg_broadcast_set_dvb_eid(broadcast, 0, NULL); + if (!(changes & EPG_CHANGED_IS_WIDESCREEN)) + save |= epg_broadcast_set_is_widescreen(broadcast, 0, NULL); + if (!(changes & EPG_CHANGED_IS_HD)) + save |= epg_broadcast_set_is_hd(broadcast, 0, NULL); + if (!(changes & EPG_CHANGED_LINES)) + save |= epg_broadcast_set_lines(broadcast, 0, NULL); + if (!(changes & EPG_CHANGED_ASPECT)) + save |= epg_broadcast_set_aspect(broadcast, 0, NULL); + if (!(changes & EPG_CHANGED_DEAFSIGNED)) + save |= epg_broadcast_set_is_deafsigned(broadcast, 0, NULL); + if (!(changes & EPG_CHANGED_SUBTITLED)) + save |= epg_broadcast_set_is_subtitled(broadcast, 0, NULL); + if (!(changes & EPG_CHANGED_AUDIO_DESC)) + save |= epg_broadcast_set_is_audio_desc(broadcast, 0, NULL); + if (!(changes & EPG_CHANGED_IS_NEW)) + save |= epg_broadcast_set_is_new(broadcast, 0, NULL); + if (!(changes & EPG_CHANGED_IS_REPEAT)) + save |= epg_broadcast_set_is_repeat(broadcast, 0, NULL); + if (!(changes & EPG_CHANGED_SUMMARY)) + save |= epg_broadcast_set_summary(broadcast, NULL, NULL); + if (!(changes & EPG_CHANGED_DESCRIPTION)) + save |= epg_broadcast_set_description(broadcast, NULL, NULL); + return save; } epg_broadcast_t *epg_broadcast_clone ( channel_t *channel, epg_broadcast_t *src, int *save ) { epg_broadcast_t *ebc; + uint32_t changes = 0; if (!src) return NULL; ebc = epg_broadcast_find_by_time(channel, src->grabber, src->start, src->stop, - src->dvb_eid, 1, save); + 1, save, &changes); if (ebc) { /* Copy metadata */ - *save |= epg_broadcast_set_is_widescreen(ebc, src->is_widescreen, NULL); - *save |= epg_broadcast_set_is_hd(ebc, src->is_hd, NULL); - *save |= epg_broadcast_set_lines(ebc, src->lines, NULL); - *save |= epg_broadcast_set_aspect(ebc, src->aspect, NULL); - *save |= epg_broadcast_set_is_deafsigned(ebc, src->is_deafsigned, NULL); - *save |= epg_broadcast_set_is_subtitled(ebc, src->is_subtitled, NULL); - *save |= epg_broadcast_set_is_audio_desc(ebc, src->is_audio_desc, NULL); - *save |= epg_broadcast_set_is_new(ebc, src->is_new, NULL); - *save |= epg_broadcast_set_is_repeat(ebc, src->is_repeat, NULL); - *save |= epg_broadcast_set_summary2(ebc, src->summary, NULL); - *save |= epg_broadcast_set_description2(ebc, src->description, NULL); - *save |= epg_broadcast_set_serieslink(ebc, src->serieslink, NULL); - *save |= epg_broadcast_set_episode(ebc, src->episode, NULL); + *save |= epg_broadcast_set_is_widescreen(ebc, src->is_widescreen, &changes); + *save |= epg_broadcast_set_is_hd(ebc, src->is_hd, &changes); + *save |= epg_broadcast_set_lines(ebc, src->lines, &changes); + *save |= epg_broadcast_set_aspect(ebc, src->aspect, &changes); + *save |= epg_broadcast_set_is_deafsigned(ebc, src->is_deafsigned, &changes); + *save |= epg_broadcast_set_is_subtitled(ebc, src->is_subtitled, &changes); + *save |= epg_broadcast_set_is_audio_desc(ebc, src->is_audio_desc, &changes); + *save |= epg_broadcast_set_is_new(ebc, src->is_new, &changes); + *save |= epg_broadcast_set_is_repeat(ebc, src->is_repeat, &changes); + *save |= epg_broadcast_set_summary(ebc, src->summary, &changes); + *save |= epg_broadcast_set_description(ebc, src->description, &changes); + *save |= epg_broadcast_set_serieslink(ebc, src->serieslink, &changes); + *save |= epg_broadcast_set_episode(ebc, src->episode, &changes); _epg_object_set_grabber(ebc, src->grabber); + *save |= epg_broadcast_change_finish(ebc, changes, 0); } return ebc; } @@ -1720,10 +1875,11 @@ void epg_broadcast_notify_running } int epg_broadcast_set_episode - ( epg_broadcast_t *broadcast, epg_episode_t *episode, epggrab_module_t *src ) + ( epg_broadcast_t *broadcast, epg_episode_t *episode, uint32_t *changed ) { int save = 0; - if (!broadcast || !_epg_object_set_grabber(broadcast, src)) return 0; + if (!broadcast) return 0; + if (changed) *changed |= EPG_CHANGED_EPISODE; if (broadcast->episode != episode) { if (broadcast->episode) _epg_episode_rem_broadcast(broadcast->episode, broadcast); @@ -1736,10 +1892,11 @@ int epg_broadcast_set_episode } int epg_broadcast_set_serieslink - ( epg_broadcast_t *ebc, epg_serieslink_t *esl, epggrab_module_t *src ) + ( epg_broadcast_t *ebc, epg_serieslink_t *esl, uint32_t *changed ) { int save = 0; - if (!ebc || !_epg_object_set_grabber(ebc, src)) return 0; + if (!ebc) return 0; + if (changed) *changed |= EPG_CHANGED_SERIESLINK; if (ebc->serieslink != esl) { if (ebc->serieslink) _epg_serieslink_rem_broadcast(ebc->serieslink, ebc); ebc->serieslink = esl; @@ -1749,97 +1906,100 @@ int epg_broadcast_set_serieslink return save; } +int epg_broadcast_set_dvb_eid + ( epg_broadcast_t *b, uint16_t dvb_eid, uint32_t *changed ) +{ + if (!b) return 0; + return _epg_object_set_u16(b, &b->dvb_eid, dvb_eid, + changed, EPG_CHANGED_DVB_EID); +} + int epg_broadcast_set_is_widescreen - ( epg_broadcast_t *b, uint8_t ws, epggrab_module_t *src ) + ( epg_broadcast_t *b, uint8_t ws, uint32_t *changed ) { if (!b) return 0; - return _epg_object_set_u8(b, &b->is_widescreen, ws, src); + return _epg_object_set_u8(b, &b->is_widescreen, ws, + changed, EPG_CHANGED_IS_WIDESCREEN); } int epg_broadcast_set_is_hd - ( epg_broadcast_t *b, uint8_t hd, epggrab_module_t *src ) + ( epg_broadcast_t *b, uint8_t hd, uint32_t *changed ) { if (!b) return 0; - return _epg_object_set_u8(b, &b->is_hd, hd, src); + return _epg_object_set_u8(b, &b->is_hd, hd, + changed, EPG_CHANGED_IS_HD); } int epg_broadcast_set_lines - ( epg_broadcast_t *b, uint16_t lines, epggrab_module_t *src ) + ( epg_broadcast_t *b, uint16_t lines, uint32_t *changed ) { if (!b) return 0; - return _epg_object_set_u16(b, &b->lines, lines, src); + return _epg_object_set_u16(b, &b->lines, lines, + changed, EPG_CHANGED_LINES); } int epg_broadcast_set_aspect - ( epg_broadcast_t *b, uint16_t aspect, epggrab_module_t *src ) + ( epg_broadcast_t *b, uint16_t aspect, uint32_t *changed ) { if (!b) return 0; - return _epg_object_set_u16(b, &b->aspect, aspect, src); + return _epg_object_set_u16(b, &b->aspect, aspect, + changed, EPG_CHANGED_ASPECT); } int epg_broadcast_set_is_deafsigned - ( epg_broadcast_t *b, uint8_t ds, epggrab_module_t *src ) + ( epg_broadcast_t *b, uint8_t ds, uint32_t *changed ) { if (!b) return 0; - return _epg_object_set_u8(b, &b->is_deafsigned, ds, src); + return _epg_object_set_u8(b, &b->is_deafsigned, ds, + changed, EPG_CHANGED_DEAFSIGNED); } int epg_broadcast_set_is_subtitled - ( epg_broadcast_t *b, uint8_t st, epggrab_module_t *src ) + ( epg_broadcast_t *b, uint8_t st, uint32_t *changed ) { if (!b) return 0; - return _epg_object_set_u8(b, &b->is_subtitled, st, src); + return _epg_object_set_u8(b, &b->is_subtitled, st, + changed, EPG_CHANGED_SUBTITLED); } int epg_broadcast_set_is_audio_desc - ( epg_broadcast_t *b, uint8_t ad, epggrab_module_t *src ) + ( epg_broadcast_t *b, uint8_t ad, uint32_t *changed ) { if (!b) return 0; - return _epg_object_set_u8(b, &b->is_audio_desc, ad, src); + return _epg_object_set_u8(b, &b->is_audio_desc, ad, + changed, EPG_CHANGED_AUDIO_DESC); } int epg_broadcast_set_is_new - ( epg_broadcast_t *b, uint8_t n, epggrab_module_t *src ) + ( epg_broadcast_t *b, uint8_t n, uint32_t *changed ) { if (!b) return 0; - return _epg_object_set_u8(b, &b->is_new, n, src); + return _epg_object_set_u8(b, &b->is_new, n, + changed, EPG_CHANGED_IS_NEW); } int epg_broadcast_set_is_repeat - ( epg_broadcast_t *b, uint8_t r, epggrab_module_t *src ) + ( epg_broadcast_t *b, uint8_t r, uint32_t *changed ) { if (!b) return 0; - return _epg_object_set_u8(b, &b->is_repeat, r, src); + return _epg_object_set_u8(b, &b->is_repeat, r, + changed, EPG_CHANGED_IS_REPEAT); } int epg_broadcast_set_summary - ( epg_broadcast_t *b, const char *str, const char *lang, - epggrab_module_t *src ) + ( epg_broadcast_t *b, const lang_str_t *str, uint32_t *changed ) { if (!b) return 0; - return _epg_object_set_lang_str(b, &b->summary, str, lang, src); + return _epg_object_set_lang_str(b, &b->summary, str, + changed, EPG_CHANGED_SUMMARY); } int epg_broadcast_set_description - ( epg_broadcast_t *b, const char *str, const char *lang, - epggrab_module_t *src ) + ( epg_broadcast_t *b, const lang_str_t *str, uint32_t *changed ) { if (!b) return 0; - return _epg_object_set_lang_str(b, &b->description, str, lang, src); -} - -int epg_broadcast_set_summary2 - ( epg_broadcast_t *b, const lang_str_t *str, epggrab_module_t *src ) -{ - if (!b || !str) return 0; - return _epg_object_set_lang_str2(b, &b->summary, str, src); -} - -int epg_broadcast_set_description2 - ( epg_broadcast_t *b, const lang_str_t *str, epggrab_module_t *src ) -{ - if (!b || !str) return 0; - return _epg_object_set_lang_str2(b, &b->description, str, src); + return _epg_object_set_lang_str(b, &b->description, str, + changed, EPG_CHANGED_DESCRIPTION); } epg_broadcast_t *epg_broadcast_get_next ( epg_broadcast_t *broadcast ) @@ -1848,21 +2008,6 @@ epg_broadcast_t *epg_broadcast_get_next ( epg_broadcast_t *broadcast ) return RB_NEXT(broadcast, sched_link); } -epg_episode_t *epg_broadcast_get_episode - ( epg_broadcast_t *ebc, int create, int *save ) -{ - char uri[256], ubuf[UUID_HEX_SIZE]; - epg_episode_t *ee; - if (!ebc) return NULL; - if (ebc->episode) return ebc->episode; - if (!create) return NULL; - snprintf(uri, sizeof(uri)-1, "tvh://channel-%s/bcast-%u/episode", - idnode_uuid_as_str(&ebc->channel->ch_id, ubuf), ebc->id); - if ((ee = epg_episode_find_by_uri(uri, 1, save))) - *save |= epg_broadcast_set_episode(ebc, ee, ebc->grabber); - return ee; -} - const char *epg_broadcast_get_title ( epg_broadcast_t *b, const char *lang ) { if (!b || !b->episode) return NULL; @@ -1938,7 +2083,7 @@ epg_broadcast_t *epg_broadcast_deserialize epg_serieslink_t *esl; lang_str_t *ls; const char *str; - uint32_t eid, u32; + uint32_t eid, u32, changes = 0, changes2 = 0; int64_t start, stop; if (htsmsg_get_s64(m, "start", &start)) return NULL; @@ -1947,63 +2092,68 @@ epg_broadcast_t *epg_broadcast_deserialize if (stop <= start) return NULL; if (stop <= dispatch_clock) return NULL; if (!(str = htsmsg_get_str(m, "episode"))) return NULL; - if (!(ee = epg_episode_find_by_uri(str, 0, NULL))) return NULL; - /* Set properties */ _epg_object_deserialize(m, (epg_object_t*)*skel); + + if (!(ee = epg_episode_find_by_uri(str, (*skel)->grabber, 0, NULL, NULL))) + return NULL; + + /* Set properties */ (*skel)->start = start; (*skel)->stop = stop; - /* Get DVB id */ - if (!htsmsg_get_u32(m, "dvb_eid", &eid)) - (*skel)->dvb_eid = eid; - /* Get channel */ if ((str = htsmsg_get_str(m, "channel"))) ch = channel_find(str); if (!ch) return NULL; /* Create */ - ebc = _epg_channel_add_broadcast(ch, skel, NULL, create, save); + ebc = _epg_channel_add_broadcast(ch, skel, (*skel)->grabber, create, save, &changes); if (!ebc) return NULL; /* Get metadata */ + if (!htsmsg_get_u32(m, "dvb_eid", &eid)) + *save |= epg_broadcast_set_dvb_eid(ebc, eid, &changes); if (!htsmsg_get_u32(m, "is_widescreen", &u32)) - *save |= epg_broadcast_set_is_widescreen(ebc, u32, NULL); + *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, NULL); + *save |= epg_broadcast_set_is_hd(ebc, u32, &changes); if (!htsmsg_get_u32(m, "lines", &u32)) - *save |= epg_broadcast_set_lines(ebc, u32, NULL); + *save |= epg_broadcast_set_lines(ebc, u32, &changes); if (!htsmsg_get_u32(m, "aspect", &u32)) - *save |= epg_broadcast_set_aspect(ebc, u32, NULL); + *save |= epg_broadcast_set_aspect(ebc, u32, &changes); if (!htsmsg_get_u32(m, "is_deafsigned", &u32)) - *save |= epg_broadcast_set_is_deafsigned(ebc, u32, NULL); + *save |= epg_broadcast_set_is_deafsigned(ebc, u32, &changes); if (!htsmsg_get_u32(m, "is_subtitled", &u32)) - *save |= epg_broadcast_set_is_subtitled(ebc, u32, NULL); + *save |= epg_broadcast_set_is_subtitled(ebc, u32, &changes); if (!htsmsg_get_u32(m, "is_audio_desc", &u32)) - *save |= epg_broadcast_set_is_audio_desc(ebc, u32, NULL); + *save |= epg_broadcast_set_is_audio_desc(ebc, u32, &changes); if (!htsmsg_get_u32(m, "is_new", &u32)) - *save |= epg_broadcast_set_is_new(ebc, u32, NULL); + *save |= epg_broadcast_set_is_new(ebc, u32, &changes); if (!htsmsg_get_u32(m, "is_repeat", &u32)) - *save |= epg_broadcast_set_is_repeat(ebc, u32, NULL); + *save |= epg_broadcast_set_is_repeat(ebc, u32, &changes); if ((ls = lang_str_deserialize(m, "summary"))) { - *save |= epg_broadcast_set_summary2(ebc, ls, NULL); + *save |= epg_broadcast_set_summary(ebc, ls, &changes); lang_str_destroy(ls); } if ((ls = lang_str_deserialize(m, "description"))) { - *save |= epg_broadcast_set_description2(ebc, ls, NULL); + *save |= epg_broadcast_set_description(ebc, ls, &changes); lang_str_destroy(ls); } /* Series link */ if ((str = htsmsg_get_str(m, "serieslink"))) - if ((esl = epg_serieslink_find_by_uri(str, 1, save))) - *save |= epg_broadcast_set_serieslink(ebc, esl, NULL); + if ((esl = epg_serieslink_find_by_uri(str, ebc->grabber, 1, save, &changes2))) { + *save |= epg_broadcast_set_serieslink(ebc, esl, &changes); + *save |= epg_serieslink_change_finish(esl, changes2, 0); + } /* Set the episode */ - *save |= epg_broadcast_set_episode(ebc, ee, NULL); + *save |= epg_broadcast_set_episode(ebc, ee, &changes); + + *save |= epg_broadcast_change_finish(ebc, changes, 0); return ebc; } diff --git a/src/epg.h b/src/epg.h index b89d86ec6..d720f3f6a 100644 --- a/src/epg.h +++ b/src/epg.h @@ -119,6 +119,15 @@ typedef enum epg_object_type } epg_object_type_t; #define EPG_TYPEMAX EPG_SERIESLINK +/* Change flags - shared */ +#define EPG_CHANGED_CREATE (1<<0) +#define EPG_CHANGED_TITLE (1<<1) +#define EPG_CHANGED_SUBTITLE (1<<2) +#define EPG_CHANGED_SUMMARY (1<<3) +#define EPG_CHANGED_DESCRIPTION (1<<4) +#define EPG_CHANGED_IMAGE (1<<5) +#define EPG_CHANGED_SLAST 2 + /* Object */ struct epg_object { @@ -155,6 +164,11 @@ epg_object_t *epg_object_deserialize ( htsmsg_t *msg, int create, int *save ); * e.g. The Simpsons, 24, Eastenders, etc... * ***********************************************************************/ +/* Change flags */ +#define EPG_CHANGED_SEASON_COUNT (1<<(EPG_CHANGED_SLAST+1)) +#define EPG_CHANGED_SEASONS (1<<(EPG_CHANGED_SLAST+2)) +#define EPG_CHANGED_EPISODES (1<<(EPG_CHANGED_SLAST+3)) + /* Object */ struct epg_brand { @@ -171,9 +185,13 @@ struct epg_brand /* Lookup */ epg_brand_t *epg_brand_find_by_uri - ( const char *uri, int create, int *save ); + ( const char *uri, struct epggrab_module *src, int create, int *save, uint32_t *changes ); epg_brand_t *epg_brand_find_by_id ( uint32_t id ); +/* Post-modify */ +int epg_brand_change_finish( epg_brand_t *b, uint32_t changed, int merge ) + __attribute__((warn_unused_result)); + /* Accessors */ const char *epg_brand_get_title ( const epg_brand_t *b, const char *lang ); @@ -182,18 +200,16 @@ const char *epg_brand_get_summary /* Mutators */ int epg_brand_set_title - ( epg_brand_t *b, const char *title, const char *lang, - struct epggrab_module *src ) + ( epg_brand_t *b, const lang_str_t *title, uint32_t *changed ) __attribute__((warn_unused_result)); int epg_brand_set_summary - ( epg_brand_t *b, const char *summary, const char *lang, - struct epggrab_module *src ) + ( epg_brand_t *b, const lang_str_t *summary, uint32_t *changed ) __attribute__((warn_unused_result)); int epg_brand_set_season_count - ( epg_brand_t *b, uint16_t season_count, struct epggrab_module *src ) + ( epg_brand_t *b, uint16_t season_count, uint32_t *changed ) __attribute__((warn_unused_result)); int epg_brand_set_image - ( epg_brand_t *b, const char *i, struct epggrab_module *src ) + ( epg_brand_t *b, const char *i, uint32_t *changed ) __attribute__((warn_unused_result)); /* Serialization */ @@ -207,6 +223,10 @@ htsmsg_t *epg_brand_list ( void ); * Season * ***********************************************************************/ +/* Change flags */ +#define EPG_CHANGED_SEASON_NUMBER (1<<(EPG_CHANGED_SLAST+1)) +#define EPG_CHANGED_EPISODE_COUNT (1<<(EPG_CHANGED_SLAST+2)) + /* Object */ struct epg_season { @@ -225,29 +245,32 @@ struct epg_season /* Lookup */ epg_season_t *epg_season_find_by_uri - ( const char *uri, int create, int *save ); + ( const char *uri, struct epggrab_module *src, int create, int *save, uint32_t *changes ); epg_season_t *epg_season_find_by_id ( uint32_t id ); +/* Post-modify */ +int epg_season_change_finish( epg_season_t *s, uint32_t changed, int merge ) + __attribute__((warn_unused_result)); + /* Accessors */ const char *epg_season_get_summary ( const epg_season_t *s, const char *lang ); /* Mutators */ int epg_season_set_summary - ( epg_season_t *s, const char *summary, const char *lang, - struct epggrab_module *src ) + ( epg_season_t *s, const lang_str_t *summary, uint32_t *changed ) __attribute__((warn_unused_result)); int epg_season_set_number - ( epg_season_t *s, uint16_t number, struct epggrab_module *src ) + ( epg_season_t *s, uint16_t number, uint32_t *changed ) __attribute__((warn_unused_result)); int epg_season_set_episode_count - ( epg_season_t *s, uint16_t episode_count, struct epggrab_module *src ) + ( epg_season_t *s, uint16_t episode_count, uint32_t *changed ) __attribute__((warn_unused_result)); int epg_season_set_brand - ( epg_season_t *s, epg_brand_t *b, struct epggrab_module *src ) + ( epg_season_t *s, epg_brand_t *b, uint32_t *changed ) __attribute__((warn_unused_result)); int epg_season_set_image - ( epg_season_t *s, const char *image, struct epggrab_module *src ) + ( epg_season_t *s, const char *image, uint32_t *changed ) __attribute__((warn_unused_result)); /* Serialization */ @@ -258,6 +281,22 @@ epg_season_t *epg_season_deserialize ( htsmsg_t *m, int create, int *save ); * Episode * ***********************************************************************/ +/* Change flags */ +#define EPG_CHANGED_GENRE (1<<(EPG_CHANGED_SLAST+1)) +#define EPG_CHANGED_EPNUM_NUM (1<<(EPG_CHANGED_SLAST+2)) +#define EPG_CHANGED_EPNUM_CNT (1<<(EPG_CHANGED_SLAST+3)) +#define EPG_CHANGED_EPPAR_NUM (1<<(EPG_CHANGED_SLAST+4)) +#define EPG_CHANGED_EPPAR_CNT (1<<(EPG_CHANGED_SLAST+5)) +#define EPG_CHANGED_EPSER_NUM (1<<(EPG_CHANGED_SLAST+6)) +#define EPG_CHANGED_EPSER_CNT (1<<(EPG_CHANGED_SLAST+7)) +#define EPG_CHANGED_EPTEXT (1<<(EPG_CHANGED_SLAST+8)) +#define EPG_CHANGED_IS_BW (1<<(EPG_CHANGED_SLAST+9)) +#define EPG_CHANGED_STAR_RATING (1<<(EPG_CHANGED_SLAST+10)) +#define EPG_CHANGED_AGE_RATING (1<<(EPG_CHANGED_SLAST+11)) +#define EPG_CHANGED_FIRST_AIRED (1<<(EPG_CHANGED_SLAST+12)) +#define EPG_CHANGED_BRAND (1<<(EPG_CHANGED_SLAST+13)) +#define EPG_CHANGED_SEASON (1<<(EPG_CHANGED_SLAST+14)) + /* Episode numbering object - this is for some back-compat and also * to allow episode information to be "collated" into easy to use object */ @@ -300,8 +339,14 @@ struct epg_episode /* Lookup */ epg_episode_t *epg_episode_find_by_uri - ( const char *uri, int create, int *save ); + ( const char *uri, struct epggrab_module *src, int create, int *save, uint32_t *changes ); epg_episode_t *epg_episode_find_by_id ( uint32_t id ); +epg_episode_t *epg_episode_find_by_broadcast + ( epg_broadcast_t *b, struct epggrab_module *src, int create, int *save, uint32_t *changes ); + +/* Post-modify */ +int epg_episode_change_finish( epg_episode_t *s, uint32_t changed, int merge ) + __attribute__((warn_unused_result)); /* Accessors */ const char *epg_episode_get_title @@ -315,60 +360,49 @@ const char *epg_episode_get_description /* Mutators */ int epg_episode_set_title - ( epg_episode_t *e, const char *title, const char *lang, - struct epggrab_module *src ) + ( epg_episode_t *e, const lang_str_t *title, uint32_t *changed ) __attribute__((warn_unused_result)); int epg_episode_set_subtitle - ( epg_episode_t *e, const char *subtitle, const char *lang, - struct epggrab_module *src ) + ( epg_episode_t *e, const lang_str_t *subtitle, uint32_t *changed ) __attribute__((warn_unused_result)); int epg_episode_set_summary - ( epg_episode_t *e, const char *summary, const char *lang, - struct epggrab_module *src ) + ( epg_episode_t *e, const lang_str_t *summary, uint32_t *changed ) __attribute__((warn_unused_result)); int epg_episode_set_description - ( epg_episode_t *e, const char *description, const char *lang, - struct epggrab_module *src ) + ( epg_episode_t *e, const lang_str_t *description, uint32_t *changed ) __attribute__((warn_unused_result)); int epg_episode_set_number - ( epg_episode_t *e, uint16_t number, struct epggrab_module *src ) + ( epg_episode_t *e, uint16_t number, uint32_t *changed ) __attribute__((warn_unused_result)); int epg_episode_set_part - ( epg_episode_t *e, uint16_t number, uint16_t count, - struct epggrab_module *src ) + ( epg_episode_t *e, uint16_t number, uint16_t count, uint32_t *changed ) __attribute__((warn_unused_result)); int epg_episode_set_epnum - ( epg_episode_t *e, epg_episode_num_t *num, struct epggrab_module *src ) + ( epg_episode_t *e, epg_episode_num_t *num, uint32_t *changed ) __attribute__((warn_unused_result)); int epg_episode_set_brand - ( epg_episode_t *e, epg_brand_t *b, struct epggrab_module *src ) + ( epg_episode_t *e, epg_brand_t *b, uint32_t *changed ) __attribute__((warn_unused_result)); int epg_episode_set_season - ( epg_episode_t *e, epg_season_t *s, struct epggrab_module *src ) + ( epg_episode_t *e, epg_season_t *s, uint32_t *changed ) __attribute__((warn_unused_result)); int epg_episode_set_genre - ( epg_episode_t *e, epg_genre_list_t *g, struct epggrab_module *src ) + ( epg_episode_t *e, epg_genre_list_t *g, uint32_t *changed ) __attribute__((warn_unused_result)); int epg_episode_set_image - ( epg_episode_t *e, const char *i, struct epggrab_module *src ) + ( epg_episode_t *e, const char *i, uint32_t *changed ) __attribute__((warn_unused_result)); int epg_episode_set_is_bw - ( epg_episode_t *e, uint8_t bw, struct epggrab_module *src ) - __attribute__((warn_unused_result)); -int epg_episode_set_title2 - ( epg_episode_t *e, const lang_str_t *str, struct epggrab_module *src ) - __attribute__((warn_unused_result)); -int epg_episode_set_subtitle2 - ( epg_episode_t *e, const lang_str_t *str, struct epggrab_module *src ) + ( epg_episode_t *e, uint8_t bw, uint32_t *changed ) __attribute__((warn_unused_result)); int epg_episode_set_first_aired - ( epg_episode_t *e, time_t aired, struct epggrab_module *src ) + ( epg_episode_t *e, time_t aired, uint32_t *changed ) __attribute__((warn_unused_result)); int epg_episode_set_star_rating - ( epg_episode_t *e, uint8_t stars, struct epggrab_module *src ) + ( epg_episode_t *e, uint8_t stars, uint32_t *changed ) __attribute__((warn_unused_result)); int epg_episode_set_age_rating - ( epg_episode_t *e, uint8_t age, struct epggrab_module *src ) + ( epg_episode_t *e, uint8_t age, uint32_t *changed ) __attribute__((warn_unused_result)); // Note: this does NOT strdup the text field @@ -415,10 +449,14 @@ struct epg_serieslink /* Lookup */ epg_serieslink_t *epg_serieslink_find_by_uri - ( const char *uri, int create, int *save ); + ( const char *uri, struct epggrab_module *src, int create, int *save, uint32_t *changes ); epg_serieslink_t *epg_serieslink_find_by_id ( uint32_t id ); +/* Post-modify */ +int epg_serieslink_change_finish( epg_serieslink_t *s, uint32_t changed, int merge ) + __attribute__((warn_unused_result)); + /* Serialization */ htsmsg_t *epg_serieslink_serialize ( epg_serieslink_t *s ); epg_serieslink_t *epg_serieslink_deserialize @@ -428,6 +466,19 @@ epg_serieslink_t *epg_serieslink_deserialize * Broadcast - specific airing (channel & time) of an episode * ***********************************************************************/ +#define EPG_CHANGED_DVB_EID (1<<(EPG_CHANGED_SLAST+1)) +#define EPG_CHANGED_IS_WIDESCREEN (1<<(EPG_CHANGED_SLAST+2)) +#define EPG_CHANGED_IS_HD (1<<(EPG_CHANGED_SLAST+3)) +#define EPG_CHANGED_LINES (1<<(EPG_CHANGED_SLAST+4)) +#define EPG_CHANGED_ASPECT (1<<(EPG_CHANGED_SLAST+5)) +#define EPG_CHANGED_DEAFSIGNED (1<<(EPG_CHANGED_SLAST+6)) +#define EPG_CHANGED_SUBTITLED (1<<(EPG_CHANGED_SLAST+7)) +#define EPG_CHANGED_AUDIO_DESC (1<<(EPG_CHANGED_SLAST+8)) +#define EPG_CHANGED_IS_NEW (1<<(EPG_CHANGED_SLAST+9)) +#define EPG_CHANGED_IS_REPEAT (1<<(EPG_CHANGED_SLAST+10)) +#define EPG_CHANGED_EPISODE (1<<(EPG_CHANGED_SLAST+11)) +#define EPG_CHANGED_SERIESLINK (1<<(EPG_CHANGED_SLAST+12)) + /* Object */ struct epg_broadcast { @@ -469,10 +520,14 @@ struct epg_broadcast /* Lookup */ epg_broadcast_t *epg_broadcast_find_by_time ( struct channel *ch, struct epggrab_module *src, - time_t start, time_t stop, uint16_t eid, int create, int *save ); + time_t start, time_t stop, int create, int *save, uint32_t *changes ); epg_broadcast_t *epg_broadcast_find_by_eid ( struct channel *ch, uint16_t eid ); epg_broadcast_t *epg_broadcast_find_by_id ( uint32_t id ); +/* Post-modify */ +int epg_broadcast_change_finish( epg_broadcast_t *b, uint32_t changed, int merge ) + __attribute__((warn_unused_result)); + /* Special */ epg_broadcast_t *epg_broadcast_clone ( struct channel *channel, epg_broadcast_t *src, int *save ); @@ -480,58 +535,51 @@ void epg_broadcast_notify_running ( epg_broadcast_t *b, epg_source_t esrc, epg_running_t running ); /* Mutators */ +int epg_broadcast_set_dvb_eid + ( epg_broadcast_t *b, uint16_t dvb_eid, uint32_t *changed ) + __attribute__((warn_unused_result)); int epg_broadcast_set_episode - ( epg_broadcast_t *b, epg_episode_t *e, struct epggrab_module *src ) + ( epg_broadcast_t *b, epg_episode_t *e, uint32_t *changed ) __attribute__((warn_unused_result)); int epg_broadcast_set_is_widescreen - ( epg_broadcast_t *b, uint8_t ws, struct epggrab_module *src ) + ( epg_broadcast_t *b, uint8_t ws, uint32_t *changed ) __attribute__((warn_unused_result)); int epg_broadcast_set_is_hd - ( epg_broadcast_t *b, uint8_t hd, struct epggrab_module *src ) + ( epg_broadcast_t *b, uint8_t hd, uint32_t *changed ) __attribute__((warn_unused_result)); int epg_broadcast_set_lines - ( epg_broadcast_t *b, uint16_t lines, struct epggrab_module *src ) + ( epg_broadcast_t *b, uint16_t lines, uint32_t *changed ) __attribute__((warn_unused_result)); int epg_broadcast_set_aspect - ( epg_broadcast_t *b, uint16_t aspect, struct epggrab_module *src ) + ( epg_broadcast_t *b, uint16_t aspect, uint32_t *changed ) __attribute__((warn_unused_result)); int epg_broadcast_set_is_deafsigned - ( epg_broadcast_t *b, uint8_t ds, struct epggrab_module *src ) + ( epg_broadcast_t *b, uint8_t ds, uint32_t *changed ) __attribute__((warn_unused_result)); int epg_broadcast_set_is_subtitled - ( epg_broadcast_t *b, uint8_t st, struct epggrab_module *src ) + ( epg_broadcast_t *b, uint8_t st, uint32_t *changed ) __attribute__((warn_unused_result)); int epg_broadcast_set_is_audio_desc - ( epg_broadcast_t *b, uint8_t ad, struct epggrab_module *src ) + ( epg_broadcast_t *b, uint8_t ad, uint32_t *changed ) __attribute__((warn_unused_result)); int epg_broadcast_set_is_new - ( epg_broadcast_t *b, uint8_t n, struct epggrab_module *src ) + ( epg_broadcast_t *b, uint8_t n, uint32_t *changed ) __attribute__((warn_unused_result)); int epg_broadcast_set_is_repeat - ( epg_broadcast_t *b, uint8_t r, struct epggrab_module *src ) + ( epg_broadcast_t *b, uint8_t r, uint32_t *changed ) __attribute__((warn_unused_result)); int epg_broadcast_set_summary - ( epg_broadcast_t *b, const char *str, const char *lang, - struct epggrab_module *src ) + ( epg_broadcast_t *b, const lang_str_t *str, uint32_t *changed ) __attribute__((warn_unused_result)); int epg_broadcast_set_description - ( epg_broadcast_t *b, const char *str, const char *lang, - struct epggrab_module *src ) - __attribute__((warn_unused_result)); -int epg_broadcast_set_summary2 - ( epg_broadcast_t *b, const lang_str_t *str, struct epggrab_module *src ) - __attribute__((warn_unused_result)); -int epg_broadcast_set_description2 - ( epg_broadcast_t *b, const lang_str_t *str, struct epggrab_module *src ) + ( epg_broadcast_t *b, const lang_str_t *str, uint32_t *changed ) __attribute__((warn_unused_result)); int epg_broadcast_set_serieslink - ( epg_broadcast_t *b, epg_serieslink_t *sl, struct epggrab_module *src ) + ( epg_broadcast_t *b, epg_serieslink_t *sl, uint32_t *changed ) __attribute__((warn_unused_result)); /* Accessors */ epg_broadcast_t *epg_broadcast_get_next ( epg_broadcast_t *b ); -epg_episode_t *epg_broadcast_get_episode - ( epg_broadcast_t *b, int create, int *save ); const char *epg_broadcast_get_title ( epg_broadcast_t *b, const char *lang ); const char *epg_broadcast_get_subtitle diff --git a/src/epggrab/module/eit.c b/src/epggrab/module/eit.c index 09e35e628..24e257535 100644 --- a/src/epggrab/module/eit.c +++ b/src/epggrab/module/eit.c @@ -415,10 +415,11 @@ static int _eit_process_event_one uint16_t eid; uint8_t dtag, dlen, running; epg_broadcast_t *ebc; - epg_episode_t *ee; + epg_episode_t *ee = NULL; epg_serieslink_t *es; epg_running_t run; eit_event_t ev; + uint32_t changes2 = 0, changes3 = 0, changes4 = 0; /* Core fields */ eid = ptr[0] << 8 | ptr[1]; @@ -434,7 +435,7 @@ static int _eit_process_event_one if ( len < dllen ) return -1; /* Find broadcast */ - ebc = epg_broadcast_find_by_time(ch, mod, start, stop, eid, 1, &save2); + ebc = epg_broadcast_find_by_time(ch, mod, start, stop, 1, &save2, &changes2); tvhtrace("eit", "svc='%s', ch='%s', eid=%5d, start=%"PRItime_t"," " stop=%"PRItime_t", ebc=%p", svc->s_dvb_svcname ?: "(null)", ch ? channel_get_name(ch) : "(null)", @@ -495,26 +496,30 @@ static int _eit_process_event_one * Broadcast */ + *save |= epg_broadcast_set_dvb_eid(ebc, eid, &changes2); + /* Summary/Description */ - if ( ev.summary ) - *save |= epg_broadcast_set_summary2(ebc, ev.summary, mod); - if ( ev.desc ) - *save |= epg_broadcast_set_description2(ebc, ev.desc, mod); + if (ev.summary) + *save |= epg_broadcast_set_summary(ebc, ev.summary, &changes2); + if (ev.desc) + *save |= epg_broadcast_set_description(ebc, ev.desc, &changes2); /* Broadcast Metadata */ - *save |= epg_broadcast_set_is_hd(ebc, ev.hd, mod); - *save |= epg_broadcast_set_is_widescreen(ebc, ev.ws, mod); - *save |= epg_broadcast_set_is_audio_desc(ebc, ev.ad, mod); - *save |= epg_broadcast_set_is_subtitled(ebc, ev.st, mod); - *save |= epg_broadcast_set_is_deafsigned(ebc, ev.ds, mod); + *save |= epg_broadcast_set_is_hd(ebc, ev.hd, &changes2); + *save |= epg_broadcast_set_is_widescreen(ebc, ev.ws, &changes2); + *save |= epg_broadcast_set_is_audio_desc(ebc, ev.ad, &changes2); + *save |= epg_broadcast_set_is_subtitled(ebc, ev.st, &changes2); + *save |= epg_broadcast_set_is_deafsigned(ebc, ev.ds, &changes2); /* * Series link */ if (*ev.suri) { - if ((es = epg_serieslink_find_by_uri(ev.suri, 1, save))) - *save |= epg_broadcast_set_serieslink(ebc, es, mod); + if ((es = epg_serieslink_find_by_uri(ev.suri, mod, 1, save, &changes3))) { + *save |= epg_broadcast_set_serieslink(ebc, es, &changes2); + *save |= epg_serieslink_change_finish(es, changes3, 0); + } } /* @@ -523,30 +528,32 @@ static int _eit_process_event_one /* Find episode */ if (*ev.uri) { - if ((ee = epg_episode_find_by_uri(ev.uri, 1, save))) - *save |= epg_broadcast_set_episode(ebc, ee, mod); - - /* Existing/Artificial */ - } else - ee = epg_broadcast_get_episode(ebc, 1, save); + ee = epg_episode_find_by_uri(ev.uri, mod, 1, save, &changes4); + } else { + ee = epg_episode_find_by_broadcast(ebc, mod, 1, save, &changes4); + } /* Update Episode */ if (ee) { - *save |= epg_episode_set_is_bw(ee, ev.bw, mod); - if ( ev.title ) - *save |= epg_episode_set_title2(ee, ev.title, mod); - if ( ev.genre ) - *save |= epg_episode_set_genre(ee, ev.genre, mod); - if ( ev.parental ) - *save |= epg_episode_set_age_rating(ee, ev.parental, mod); - if ( ev.summary ) - *save |= epg_episode_set_subtitle2(ee, ev.summary, mod); + *save |= epg_broadcast_set_episode(ebc, ee, &changes2); + *save |= epg_episode_set_is_bw(ee, ev.bw, &changes4); + if (ev.title) + *save |= epg_episode_set_title(ee, ev.title, &changes4); + if (ev.genre) + *save |= epg_episode_set_genre(ee, ev.genre, &changes4); + if (ev.parental) + *save |= epg_episode_set_age_rating(ee, ev.parental, &changes4); + if (ev.summary) + *save |= epg_episode_set_subtitle(ee, ev.summary, &changes4); #if TODO_ADD_EXTRA - if ( ev.extra ) - *save |= epg_episode_set_extra(ee, extra, mod); + if (ev.extra) + *save |= epg_episode_set_extra(ee, extra, &changes4); #endif + *save |= epg_episode_change_finish(ee, changes4, 0); } + *save |= epg_broadcast_change_finish(ebc, changes2, 0); + /* Tidy up */ #if TODO_ADD_EXTRA if (ev.extra) htsmsg_destroy(ev.extra); diff --git a/src/epggrab/module/opentv.c b/src/epggrab/module/opentv.c index 4013aa363..e7129a9a6 100644 --- a/src/epggrab/module/opentv.c +++ b/src/epggrab/module/opentv.c @@ -310,7 +310,7 @@ opentv_parse_event_section_one channel_t *ch, const char *lang, const uint8_t *buf, int len ) { - int i, r, save = 0; + int i, r, save = 0, merge; opentv_module_t *mod = sta->os_mod; epggrab_module_t *src = (epggrab_module_t*)mod; epg_broadcast_t *ebc; @@ -318,6 +318,8 @@ opentv_parse_event_section_one epg_serieslink_t *es; opentv_event_t ev; char buffer[2048]; + lang_str_t *ls; + uint32_t changes, changes2, changes3; /* Loop around event entries */ i = 7; @@ -331,16 +333,22 @@ opentv_parse_event_section_one * Broadcast */ + merge = changes = changes2 = changes3 = 0; + /* Find broadcast */ if (ev.start && ev.stop) { ebc = epg_broadcast_find_by_time(ch, src, ev.start, ev.stop, - ev.eid, 1, &save); + 1, &save, &changes); tvhdebug("opentv", "find by time start %"PRItime_t " stop " "%"PRItime_t " eid %d = %p", ev.start, ev.stop, ev.eid, ebc); + save |= epg_broadcast_set_dvb_eid(ebc, ev.eid, &changes); } else { ebc = epg_broadcast_find_by_eid(ch, ev.eid); tvhdebug("opentv", "find by eid %d = %p", ev.eid, ebc); + if (ebc && ebc->grabber != src) + goto done; + merge = 1; } if (!ebc) goto done; @@ -348,11 +356,15 @@ opentv_parse_event_section_one /* Summary / Description */ if (ev.summary) { tvhdebug("opentv", " summary '%s'", ev.summary); - save |= epg_broadcast_set_summary(ebc, ev.summary, lang, src); + ls = lang_str_create2(ev.summary, lang); + save |= epg_broadcast_set_summary(ebc, ls, &changes); + lang_str_destroy(ls); } if (ev.desc) { tvhdebug("opentv", " desc '%s'", ev.desc); - save |= epg_broadcast_set_description(ebc, ev.desc, lang, src); + ls = lang_str_create2(ev.desc, lang); + save |= epg_broadcast_set_description(ebc, ls, &changes); + lang_str_destroy(ls); } /* @@ -363,15 +375,18 @@ opentv_parse_event_section_one char suri[257], ubuf[UUID_HEX_SIZE]; snprintf(suri, 256, "opentv://channel-%s/series-%d", channel_get_uuid(ch, ubuf), ev.serieslink); - if ((es = epg_serieslink_find_by_uri(suri, 1, &save))) - save |= epg_broadcast_set_serieslink(ebc, es, src); + if ((es = epg_serieslink_find_by_uri(suri, src, 1, &save, &changes2))) { + save |= epg_broadcast_set_serieslink(ebc, es, &changes); + save |= epg_serieslink_change_finish(es, changes2, merge); + } } /* * Episode */ - if ((ee = epg_broadcast_get_episode(ebc, 1, &save))) { + if ((ee = epg_episode_find_by_broadcast(ebc, src, 1, &save, &changes3))) { + save |= epg_broadcast_set_episode(ebc, ee, &changes); tvhdebug("opentv", " find episode %p", ee); if (ev.title) { tvhdebug("opentv", " title '%s'", ev.title); @@ -379,14 +394,19 @@ opentv_parse_event_section_one /* try to cleanup the title */ if (_opentv_apply_pattern_list(buffer, sizeof(buffer), ev.title, &mod->p_cleanup_title)) { tvhtrace("opentv", " clean title '%s'", buffer); - save |= epg_episode_set_title(ee, buffer, lang, src); - } else - save |= epg_episode_set_title(ee, ev.title, lang, src); + ls = lang_str_create2(buffer, lang); + save |= epg_episode_set_title(ee, ls, &changes3); + lang_str_destroy(ls); + } else { + ls = lang_str_create2(buffer, lang); + save |= epg_episode_set_title(ee, ls, &changes3); + lang_str_destroy(ls); + } } if (ev.cat) { epg_genre_list_t *egl = calloc(1, sizeof(epg_genre_list_t)); epg_genre_list_add_by_eit(egl, ev.cat); - save |= epg_episode_set_genre(ee, egl, src); + save |= epg_episode_set_genre(ee, egl, &changes3); epg_genre_list_destroy(egl); } if (ev.summary) { @@ -413,16 +433,21 @@ opentv_parse_event_section_one } /* save any found number */ if (en.s_num || en.e_num || en.p_num) - save |= epg_episode_set_epnum(ee, &en, src); + save |= epg_episode_set_epnum(ee, &en, &changes3); /* ...for subtitle */ if (_opentv_apply_pattern_list(buffer, sizeof(buffer), ev.summary, &mod->p_subt)) { tvhtrace("opentv", " extract subtitle '%s'", buffer); - save |= epg_episode_set_subtitle(ee, buffer, lang, src); + ls = lang_str_create2(buffer, lang); + save |= epg_episode_set_subtitle(ee, ls, &changes3); + lang_str_destroy(ls); } } + save |= epg_broadcast_change_finish(ebc, changes, merge); } + save |= epg_broadcast_change_finish(ebc, changes, merge); + /* Cleanup */ done: if (ev.title) free(ev.title); diff --git a/src/epggrab/module/psip.c b/src/epggrab/module/psip.c index ef73c6d76..60276af89 100644 --- a/src/epggrab/module/psip.c +++ b/src/epggrab/module/psip.c @@ -341,13 +341,14 @@ _psip_eit_callback_channel uint16_t eventid; uint32_t starttime, length; time_t start, stop; - int save = 0, save2, i, size; + int save = 0, save2, save3, i, size; uint8_t titlelen; unsigned int dlen; epg_broadcast_t *ebc; epg_episode_t *ee; lang_str_t *title, *description; psip_desc_t *pd; + uint32_t changes2, changes3; epggrab_module_t *mod = (epggrab_module_t *)ps->ps_mod; for (i = 0; len >= 12 && i < count; len -= size, ptr += size, i++) { @@ -384,23 +385,34 @@ _psip_eit_callback_channel i, ch ? channel_get_name(ch) : "(null)", eventid, start, length, lang_str_get(title, NULL), titlelen); - ebc = epg_broadcast_find_by_time(ch, mod, start, stop, eventid, 1, &save2); + save2 = save3 = changes2 = changes3 = 0; + + ebc = epg_broadcast_find_by_time(ch, mod, start, stop, 1, &save2, &changes2); tvhtrace("psip", " eid=%5d, start=%"PRItime_t", stop=%"PRItime_t", ebc=%p", eventid, start, stop, ebc); if (!ebc) goto next; - save |= save2; + + save2 |= epg_broadcast_set_dvb_eid(ebc, eventid, &changes2); pd = psip_find_desc(ps, eventid); if (pd) { description = atsc_get_string(pd->pd_data, pd->pd_datalen); if (description) { - save |= epg_broadcast_set_description2(ebc, description, mod); + save2 |= epg_broadcast_set_description(ebc, description, &changes2); lang_str_destroy(description); } } - ee = epg_broadcast_get_episode(ebc, 1, &save2); - save |= epg_episode_set_title2(ee, title, mod); + ee = epg_episode_find_by_broadcast(ebc, mod, 1, &save3, &changes3); + if (ee) { + save2 |= epg_broadcast_set_episode(ebc, ee, &changes2); + save3 |= epg_episode_set_title(ee, title, &changes3); + save3 |= epg_episode_change_finish(ee, changes3, 0); + } + + save |= epg_broadcast_change_finish(ebc, changes2, 0); + + save |= save2 | save3; next: lang_str_destroy(title); @@ -538,6 +550,7 @@ _psip_ett_callback lang_str_t *description; idnode_list_mapping_t *ilm; channel_t *ch; + uint32_t changes; /* Validate */ if (tableid != 0xcc) return -1; @@ -585,9 +598,11 @@ _psip_ett_callback LIST_FOREACH(ilm, &svc->s_channels, ilm_in1_link) { ch = (channel_t *)ilm->ilm_in2; epg_broadcast_t *ebc; + changes = 0; ebc = epg_broadcast_find_by_eid(ch, eventid); - if (ebc) { - save |= epg_broadcast_set_description2(ebc, description, mod); + if (ebc && ebc->grabber == mod) { + save |= epg_broadcast_set_description(ebc, description, &changes); + save |= epg_broadcast_change_finish(ebc, changes, 1); tvhtrace("psip", "0x%04x: ETT tableid 0x%04X [%s], eventid 0x%04X (%d) ['%s'], ver %d", mt->mt_pid, tsid, svc->s_dvb_svcname, eventid, eventid, lang_str_get(ebc->episode->title, "eng"), ver); diff --git a/src/epggrab/module/pyepg.c b/src/epggrab/module/pyepg.c index 3f3ad0686..54cc37f4f 100644 --- a/src/epggrab/module/pyepg.c +++ b/src/epggrab/module/pyepg.c @@ -100,7 +100,8 @@ static int _pyepg_parse_brand htsmsg_t *attr, *tags; epg_brand_t *brand; const char *str; - uint32_t u32; + lang_str_t *ls; + uint32_t u32, changes = 0; if ( data == NULL ) return 0; @@ -109,32 +110,42 @@ static int _pyepg_parse_brand if ((tags = htsmsg_get_map(data, "tags")) == NULL) return 0; /* Find brand */ - if ((brand = epg_brand_find_by_uri(str, 1, &save)) == NULL) return 0; + if ((brand = epg_brand_find_by_uri(str, mod, 1, &save, &changes)) == NULL) + return 0; stats->brands.total++; if (save) stats->brands.created++; /* Set title */ if ((str = htsmsg_xml_get_cdata_str(tags, "title"))) { - save |= epg_brand_set_title(brand, str, NULL, mod); + ls = lang_str_create2(str, NULL); + save |= epg_brand_set_title(brand, ls, &changes); + lang_str_destroy(ls); } /* Set summary */ if ((str = htsmsg_xml_get_cdata_str(tags, "summary"))) { - save |= epg_brand_set_summary(brand, str, NULL, mod); + ls = lang_str_create2(str, NULL); + save |= epg_brand_set_summary(brand, ls, &changes); + lang_str_destroy(ls); } /* Set image */ if ((str = htsmsg_xml_get_cdata_str(tags, "image"))) { - save |= epg_brand_set_image(brand, str, mod); + ls = lang_str_create2(str, NULL); + save |= epg_brand_set_image(brand, str, &changes); + lang_str_destroy(ls); } else if ((str = htsmsg_xml_get_cdata_str(tags, "thumb"))) { - save |= epg_brand_set_image(brand, str, mod); + ls = lang_str_create2(str, NULL); + save |= epg_brand_set_image(brand, str, &changes); + lang_str_destroy(ls); } /* Set season count */ if (htsmsg_xml_get_cdata_u32(tags, "series-count", &u32) == 0) { - save |= epg_brand_set_season_count(brand, u32, mod); + save |= epg_brand_set_season_count(brand, u32, &changes); } + save |= epg_brand_change_finish(brand, changes, 0); if (save) stats->brands.modified++; return save; @@ -148,7 +159,8 @@ static int _pyepg_parse_season epg_season_t *season; epg_brand_t *brand; const char *str; - uint32_t u32; + lang_str_t *ls; + uint32_t u32, changes = 0; if ( data == NULL ) return 0; @@ -157,40 +169,43 @@ static int _pyepg_parse_season if ((tags = htsmsg_get_map(data, "tags")) == NULL) return 0; /* Find series */ - if ((season = epg_season_find_by_uri(str, 1, &save)) == NULL) return 0; + if ((season = epg_season_find_by_uri(str, mod, 1, &save, &changes)) == NULL) + return 0; stats->seasons.total++; if (save) stats->seasons.created++; /* Set brand */ if ((str = htsmsg_get_str(attr, "brand"))) { - if ((brand = epg_brand_find_by_uri(str, 0, NULL))) { - save |= epg_season_set_brand(season, brand, mod); + if ((brand = epg_brand_find_by_uri(str, mod, 0, NULL, NULL))) { + save |= epg_season_set_brand(season, brand, &changes); } } /* Set summary */ if ((str = htsmsg_xml_get_cdata_str(tags, "summary"))) { - save |= epg_season_set_summary(season, str, NULL, mod); + ls = lang_str_create2(str, NULL); + save |= epg_season_set_summary(season, ls, &changes); + lang_str_destroy(ls); } /* Set image */ - if ((str = htsmsg_xml_get_cdata_str(tags, "image"))) { - save |= epg_season_set_image(season, str, mod); - } else if ((str = htsmsg_xml_get_cdata_str(tags, "thumb"))) { - save |= epg_season_set_image(season, str, mod); + if ((str = htsmsg_xml_get_cdata_str(tags, "image")) || + (str = htsmsg_xml_get_cdata_str(tags, "thumb"))) { + save |= epg_season_set_image(season, str, &changes); } /* Set season number */ if (htsmsg_xml_get_cdata_u32(tags, "number", &u32) == 0) { - save |= epg_season_set_number(season, u32, mod); + save |= epg_season_set_number(season, u32, &changes); } /* Set episode count */ if (htsmsg_xml_get_cdata_u32(tags, "episode-count", &u32) == 0) { - save |= epg_season_set_episode_count(season, u32, mod); + save |= epg_season_set_episode_count(season, u32, &changes); } - if(save) stats->seasons.modified++; + save |= epg_season_change_finish(season, changes, 0); + if (save) stats->seasons.modified++; return save; } @@ -204,7 +219,8 @@ static int _pyepg_parse_episode epg_season_t *season; epg_brand_t *brand; const char *str; - uint32_t u32, pc, pn; + lang_str_t *ls; + uint32_t u32, pc, pn, changes = 0; epg_genre_list_t *egl; if ( data == NULL ) return 0; @@ -214,64 +230,70 @@ static int _pyepg_parse_episode if ((tags = htsmsg_get_map(data, "tags")) == NULL) return 0; /* Find episode */ - if ((episode = epg_episode_find_by_uri(str, 1, &save)) == NULL) return 0; + if ((episode = epg_episode_find_by_uri(str, mod, 1, &save, &changes)) == NULL) return 0; stats->episodes.total++; if (save) stats->episodes.created++; /* Set season */ if ((str = htsmsg_get_str(attr, "series"))) { - if ((season = epg_season_find_by_uri(str, 0, NULL))) { - save |= epg_episode_set_season(episode, season, mod); + if ((season = epg_season_find_by_uri(str, mod, 0, NULL, NULL))) { + save |= epg_episode_set_season(episode, season, &changes); } } /* Set brand */ if ((str = htsmsg_get_str(attr, "brand"))) { - if ((brand = epg_brand_find_by_uri(str, 0, NULL))) { - save |= epg_episode_set_brand(episode, brand, mod); + if ((brand = epg_brand_find_by_uri(str, mod, 0, NULL, NULL))) { + save |= epg_episode_set_brand(episode, brand, &changes); } } /* Set title/subtitle */ if ((str = htsmsg_xml_get_cdata_str(tags, "title"))) { - save |= epg_episode_set_title(episode, str, NULL, mod); + ls = lang_str_create2(str, NULL); + save |= epg_episode_set_title(episode, ls, &changes); + lang_str_destroy(ls); } if ((str = htsmsg_xml_get_cdata_str(tags, "subtitle"))) { - save |= epg_episode_set_subtitle(episode, str, NULL, mod); + ls = lang_str_create2(str, NULL); + save |= epg_episode_set_subtitle(episode, ls, &changes); + lang_str_destroy(ls); } /* Set summary */ if ((str = htsmsg_xml_get_cdata_str(tags, "summary"))) { - save |= epg_episode_set_summary(episode, str, NULL, mod); + ls = lang_str_create2(str, NULL); + save |= epg_episode_set_summary(episode, ls, &changes); + lang_str_destroy(ls); } /* Number */ if (htsmsg_xml_get_cdata_u32(tags, "number", &u32) == 0) { - save |= epg_episode_set_number(episode, u32, mod); + save |= epg_episode_set_number(episode, u32, &changes); } if (!htsmsg_xml_get_cdata_u32(tags, "part-number", &pn)) { pc = 0; htsmsg_xml_get_cdata_u32(tags, "part-count", &pc); - save |= epg_episode_set_part(episode, pn, pc, mod); + save |= epg_episode_set_part(episode, pn, pc, &changes); } /* Set image */ - if ((str = htsmsg_xml_get_cdata_str(tags, "image"))) { - save |= epg_episode_set_image(episode, str, mod); - } else if ((str = htsmsg_xml_get_cdata_str(tags, "thumb"))) { - save |= epg_episode_set_image(episode, str, mod); + if ((str = htsmsg_xml_get_cdata_str(tags, "image")) || + (str = htsmsg_xml_get_cdata_str(tags, "thumb"))) { + save |= epg_episode_set_image(episode, str, &changes); } /* Genre */ if ((egl = _pyepg_parse_genre(tags))) { - save |= epg_episode_set_genre(episode, egl, mod); + save |= epg_episode_set_genre(episode, egl, &changes); epg_genre_list_destroy(egl); } /* Content */ if ((htsmsg_get_map(tags, "blackandwhite"))) - save |= epg_episode_set_is_bw(episode, 1, mod); + save |= epg_episode_set_is_bw(episode, 1, &changes); + save |= epg_episode_change_finish(episode, changes, 0); if (save) stats->episodes.modified++; return save; @@ -287,7 +309,7 @@ static int _pyepg_parse_broadcast epg_broadcast_t *broadcast; const char *id, *start, *stop; time_t tm_start, tm_stop; - uint32_t u32; + uint32_t u32, changes = 0; if ( data == NULL || channel == NULL ) return 0; @@ -302,33 +324,34 @@ static int _pyepg_parse_broadcast if (!_pyepg_parse_time(stop, &tm_stop)) return 0; /* Find broadcast */ - broadcast - = epg_broadcast_find_by_time(channel, mod, tm_start, tm_stop, 0, 1, &save); + broadcast = epg_broadcast_find_by_time(channel, mod, tm_start, tm_stop, + 1, &save, &changes); if ( broadcast == NULL ) return 0; stats->broadcasts.total++; if ( save ) stats->broadcasts.created++; /* Quality */ u32 = htsmsg_get_map(tags, "hd") ? 1 : 0; - save |= epg_broadcast_set_is_hd(broadcast, u32, mod); + save |= epg_broadcast_set_is_hd(broadcast, u32, &changes); u32 = htsmsg_get_map(tags, "widescreen") ? 1 : 0; - save |= epg_broadcast_set_is_widescreen(broadcast, u32, mod); + save |= epg_broadcast_set_is_widescreen(broadcast, u32, &changes); // TODO: lines, aspect /* Accessibility */ // Note: reuse XMLTV parse code as this is the same - xmltv_parse_accessibility(mod, broadcast, tags); + xmltv_parse_accessibility(broadcast, tags, &changes); /* New/Repeat */ u32 = htsmsg_get_map(tags, "new") || htsmsg_get_map(tags, "premiere"); - save |= epg_broadcast_set_is_new(broadcast, u32, mod); + save |= epg_broadcast_set_is_new(broadcast, u32, &changes); u32 = htsmsg_get_map(tags, "repeat") ? 1 : 0; - save |= epg_broadcast_set_is_repeat(broadcast, u32, mod); + save |= epg_broadcast_set_is_repeat(broadcast, u32, &changes); /* Set episode */ - if ((episode = epg_episode_find_by_uri(id, 1, &save)) == NULL) return 0; - save |= epg_broadcast_set_episode(broadcast, episode, mod); + if ((episode = epg_episode_find_by_uri(id, mod, 1, &save, &changes)) == NULL) return 0; + save |= epg_broadcast_set_episode(broadcast, episode, &changes); + save |= epg_broadcast_change_finish(broadcast, changes, 0); if (save) stats->broadcasts.modified++; return save; diff --git a/src/epggrab/module/xmltv.c b/src/epggrab/module/xmltv.c index 98fa37c55..d1da228d4 100644 --- a/src/epggrab/module/xmltv.c +++ b/src/epggrab/module/xmltv.c @@ -217,8 +217,9 @@ static void parse_xmltv_dd_progid * */ static void get_episode_info - (epggrab_module_t *mod, - htsmsg_t *tags, char **uri, char **suri, epg_episode_num_t *epnum ) + ( epggrab_module_t *mod, + htsmsg_t *tags, char **uri, char **suri, + epg_episode_num_t *epnum ) { htsmsg_field_t *f; htsmsg_t *c, *a; @@ -249,7 +250,7 @@ static void get_episode_info */ static int xmltv_parse_vid_quality - ( epggrab_module_t *mod, epg_broadcast_t *ebc, htsmsg_t *m, int8_t *bw ) + ( epg_broadcast_t *ebc, htsmsg_t *m, int8_t *bw, uint32_t *changes ) { int save = 0; int hd = 0, lines = 0, aspect = 0; @@ -293,13 +294,13 @@ xmltv_parse_vid_quality aspect = (100 * w) / h; } } - save |= epg_broadcast_set_is_hd(ebc, hd, mod); + save |= epg_broadcast_set_is_hd(ebc, hd, changes); if (aspect) { - save |= epg_broadcast_set_is_widescreen(ebc, hd || aspect > 137, mod); - save |= epg_broadcast_set_aspect(ebc, aspect, mod); + save |= epg_broadcast_set_is_widescreen(ebc, hd || aspect > 137, changes); + save |= epg_broadcast_set_aspect(ebc, aspect, changes); } if (lines) - save |= epg_broadcast_set_lines(ebc, lines, mod); + save |= epg_broadcast_set_lines(ebc, lines, changes); return save; } @@ -309,7 +310,7 @@ xmltv_parse_vid_quality */ int xmltv_parse_accessibility - ( epggrab_module_t *mod, epg_broadcast_t *ebc, htsmsg_t *m ) + ( epg_broadcast_t *ebc, htsmsg_t *m, uint32_t *changes ) { int save = 0; htsmsg_t *tag; @@ -321,12 +322,12 @@ xmltv_parse_accessibility if ((tag = htsmsg_get_map_by_field(f))) { str = htsmsg_xml_get_attr_str(tag, "type"); if (str && !strcmp(str, "teletext")) - save |= epg_broadcast_set_is_subtitled(ebc, 1, mod); + save |= epg_broadcast_set_is_subtitled(ebc, 1, changes); else if (str && !strcmp(str, "deaf-signed")) - save |= epg_broadcast_set_is_deafsigned(ebc, 1, mod); + save |= epg_broadcast_set_is_deafsigned(ebc, 1, changes); } } else if (!strcmp(f->hmf_name, "audio-described")) { - save |= epg_broadcast_set_is_audio_desc(ebc, 1, mod); + save |= epg_broadcast_set_is_audio_desc(ebc, 1, changes); } } return save; @@ -336,13 +337,13 @@ xmltv_parse_accessibility * Previously shown */ static int _xmltv_parse_previously_shown - ( epggrab_module_t *mod, epg_broadcast_t *ebc, htsmsg_t *tag, - time_t *first_aired ) + ( epg_broadcast_t *ebc, time_t *first_aired, + htsmsg_t *tag, uint32_t *changes ) { int ret; const char *start; - if (!mod || !ebc || !tag) return 0; - ret = epg_broadcast_set_is_repeat(ebc, 1, mod); + if (!ebc || !tag) return 0; + ret = epg_broadcast_set_is_repeat(ebc, 1, changes); if ((start = htsmsg_xml_get_attr_str(tag, "start"))) *first_aired = _xmltv_str2time(start); return ret; @@ -355,14 +356,14 @@ static int _xmltv_parse_previously_shown * */ static int _xmltv_parse_star_rating - ( epggrab_module_t *mod, epg_episode_t *ee, htsmsg_t *body ) + ( epg_episode_t *ee, htsmsg_t *body, uint32_t *changes ) { double a, b; htsmsg_t *stars, *tags; const char *s1, *s2; char *s1end, *s2end; - if (!mod || !ee || !body) return 0; + if (!ee || !body) return 0; if (!(stars = htsmsg_get_map(body, "star-rating"))) return 0; if (!(tags = htsmsg_get_map(stars, "tags"))) return 0; if (!(s1 = htsmsg_xml_get_cdata_str(tags, "value"))) return 0; @@ -372,7 +373,7 @@ static int _xmltv_parse_star_rating b = strtod(s2 + 1, &s2end); if ( a == 0.0f || b == 0.0f) return 0; - return epg_episode_set_star_rating(ee, (100 * a) / b, mod); + return epg_episode_set_star_rating(ee, (100 * a) / b, changes); } /* @@ -397,20 +398,20 @@ static int _xmltv_parse_star_rating * [rating system=advisory] values "strong sexual content","Language", etc */ static int _xmltv_parse_age_rating - ( epggrab_module_t *mod, epg_episode_t *ee, htsmsg_t *body ) + ( epg_episode_t *ee, htsmsg_t *body, uint32_t *changes ) { uint8_t age; htsmsg_t *rating, *tags; const char *s1; - if (!mod || !ee || !body) return 0; + if (!ee || !body) return 0; if (!(rating = htsmsg_get_map(body, "rating"))) return 0; if (!(tags = htsmsg_get_map(rating, "tags"))) return 0; if (!(s1 = htsmsg_xml_get_cdata_str(tags, "value"))) return 0; age = atoi(s1); - return epg_episode_set_age_rating(ee, age, mod); + return epg_episode_set_age_rating(ee, age, changes); } /* @@ -473,11 +474,12 @@ static int _xmltv_parse_programme_tags lang_str_t *subtitle = NULL; time_t first_aired = 0; int8_t bw = -1; + uint32_t changes = 0, changes2 = 0, changes3 = 0; /* * Broadcast */ - if (!(ebc = epg_broadcast_find_by_time(ch, mod, start, stop, 0, 1, &save))) + if (!(ebc = epg_broadcast_find_by_time(ch, mod, start, stop, 1, &save, &changes))) return 0; stats->broadcasts.total++; if (save) stats->broadcasts.created++; @@ -485,21 +487,21 @@ static int _xmltv_parse_programme_tags /* Description (wait for episode first) */ _xmltv_parse_lang_str(&desc, tags, "desc"); if (desc) - save3 |= epg_broadcast_set_description2(ebc, desc, mod); + save3 |= epg_broadcast_set_description(ebc, desc, &changes); /* Quality metadata */ - save |= xmltv_parse_vid_quality(mod, ebc, htsmsg_get_map(tags, "video"), &bw); + save |= xmltv_parse_vid_quality(ebc, htsmsg_get_map(tags, "video"), &bw, &changes); /* Accessibility */ - save |= xmltv_parse_accessibility(mod, ebc, tags); + save |= xmltv_parse_accessibility(ebc, tags, &changes); /* Misc */ - save |= _xmltv_parse_previously_shown(mod, ebc, + save |= _xmltv_parse_previously_shown(ebc, &first_aired, htsmsg_get_map(tags, "previously-shown"), - &first_aired); + &changes); if (htsmsg_get_map(tags, "premiere") || htsmsg_get_map(tags, "new")) - save |= epg_broadcast_set_is_new(ebc, 1, mod); + save |= epg_broadcast_set_is_new(ebc, 1, &changes); /* * Episode/Series info @@ -510,25 +512,24 @@ static int _xmltv_parse_programme_tags * Series Link */ if (suri) { - es = epg_serieslink_find_by_uri(suri, 1, &save2); + if ((es = epg_serieslink_find_by_uri(suri, mod, 1, &save2, &changes2))) { + save |= epg_broadcast_set_serieslink(ebc, es, &changes); + save |= epg_serieslink_change_finish(es, changes2, 0); + } free(suri); if (es) stats->seasons.total++; if (save2) stats->seasons.created++; - - if (es) - save |= epg_broadcast_set_serieslink(ebc, es, mod); } /* * Episode */ if (uri) { - if ((ee = epg_episode_find_by_uri(uri, 1, &save3))) - save |= epg_broadcast_set_episode(ebc, ee, mod); - free(uri); + ee = epg_episode_find_by_uri(uri, mod, 1, &save3, &changes3); } else { - ee = epg_broadcast_get_episode(ebc, 1, &save3); + ee = epg_episode_find_by_broadcast(ebc, mod, 1, &save3, &changes3); } + save |= epg_broadcast_set_episode(ebc, ee, &changes); if (ee) stats->episodes.total++; if (save3) stats->episodes.created++; @@ -537,28 +538,34 @@ static int _xmltv_parse_programme_tags _xmltv_parse_lang_str(&subtitle, tags, "sub-title"); if (title) - save3 |= epg_episode_set_title2(ee, title, mod); + save3 |= epg_episode_set_title(ee, title, &changes3); if (subtitle) - save3 |= epg_episode_set_subtitle2(ee, subtitle, mod); + save3 |= epg_episode_set_subtitle(ee, subtitle, &changes3); if ((egl = _xmltv_parse_categories(tags))) { - save3 |= epg_episode_set_genre(ee, egl, mod); + save3 |= epg_episode_set_genre(ee, egl, &changes3); epg_genre_list_destroy(egl); } if (bw != -1) - save3 |= epg_episode_set_is_bw(ee, (uint8_t)bw, mod); + save3 |= epg_episode_set_is_bw(ee, (uint8_t)bw, &changes3); - save3 |= epg_episode_set_epnum(ee, &epnum, mod); + save3 |= epg_episode_set_epnum(ee, &epnum, &changes3); - save3 |= _xmltv_parse_star_rating(mod, ee, tags); + save3 |= _xmltv_parse_star_rating(ee, tags, &changes3); - save3 |= _xmltv_parse_age_rating(mod, ee, tags); + save3 |= _xmltv_parse_age_rating(ee, tags, &changes3); if (icon) - save3 |= epg_episode_set_image(ee, icon, mod); + save3 |= epg_episode_set_image(ee, icon, &changes3); + + save3 |= epg_episode_set_first_aired(ee, first_aired, &changes3); + + save3 |= epg_episode_change_finish(ee, changes3, 0); } + save |= epg_broadcast_change_finish(ebc, changes, 0); + /* Stats */ if (save) stats->broadcasts.modified++; if (save2) stats->seasons.modified++; diff --git a/src/epggrab/private.h b/src/epggrab/private.h index 2625c1b8a..5221801e7 100644 --- a/src/epggrab/private.h +++ b/src/epggrab/private.h @@ -176,11 +176,11 @@ epggrab_ota_service_del /* Note: this is reused by pyepg since they share a common format */ int xmltv_parse_accessibility - ( epggrab_module_t *mod, epg_broadcast_t *ebc, htsmsg_t *m ); + ( epg_broadcast_t *ebc, htsmsg_t *m, uint32_t *changes ); /* Freesat huffman decoder */ size_t freesat_huffman_decode - (char *dst, size_t* dstlen, const uint8_t *src, size_t srclen); + ( char *dst, size_t* dstlen, const uint8_t *src, size_t srclen ); /* ************************************************************************** * Module setup(s) diff --git a/src/lang_str.c b/src/lang_str.c index 24a85fd20..eb040de50 100644 --- a/src/lang_str.c +++ b/src/lang_str.c @@ -46,6 +46,14 @@ lang_str_t *lang_str_create ( void ) return calloc(1, sizeof(lang_str_t)); } +lang_str_t *lang_str_create2 ( const char *s, const char *lang ) +{ + lang_str_t *ls = lang_str_create(); + if (ls) + lang_str_add(ls, s, lang, 0); + return ls; +} + /* Destroy (free memory) */ void lang_str_destroy ( lang_str_t *ls ) { @@ -72,7 +80,7 @@ lang_str_t *lang_str_copy ( const lang_str_t *ls ) /* Get language element */ lang_str_ele_t *lang_str_get2 - ( lang_str_t *ls, const char *lang ) + ( const lang_str_t *ls, const char *lang ) { int i; const char **langs; @@ -101,7 +109,7 @@ lang_str_ele_t *lang_str_get2 /* Get string */ const char *lang_str_get - ( lang_str_t *ls, const char *lang ) + ( const lang_str_t *ls, const char *lang ) { lang_str_ele_t *e = lang_str_get2(ls, lang); return e ? e->str : NULL; @@ -255,7 +263,7 @@ lang_str_t *lang_str_deserialize ( htsmsg_t *m, const char *n ) } /* Compare */ -int lang_str_compare( lang_str_t *ls1, lang_str_t *ls2 ) +int lang_str_compare( const lang_str_t *ls1, const lang_str_t *ls2 ) { lang_str_ele_t *e; const char *s1, *s2; diff --git a/src/lang_str.h b/src/lang_str.h index 206fe3000..d8e3b5f6c 100644 --- a/src/lang_str.h +++ b/src/lang_str.h @@ -34,11 +34,12 @@ typedef RB_HEAD(lang_str, lang_str_ele) lang_str_t; /* Create/Destroy */ void lang_str_destroy ( lang_str_t *ls ); lang_str_t *lang_str_create ( void ); +lang_str_t *lang_str_create2 ( const char *str, const char *lang ); lang_str_t *lang_str_copy ( const lang_str_t *ls ); /* Get elements */ -const char *lang_str_get ( lang_str_t *ls, const char *lang ); -lang_str_ele_t *lang_str_get2 ( lang_str_t *ls, const char *lang ); +const char *lang_str_get ( const lang_str_t *ls, const char *lang ); +lang_str_ele_t *lang_str_get2 ( const lang_str_t *ls, const char *lang ); /* Add/Update elements */ int lang_str_add @@ -61,7 +62,7 @@ lang_str_t *lang_str_deserialize ( htsmsg_t *m, const char *f ); /* Compare */ -int lang_str_compare ( lang_str_t *ls1, lang_str_t *ls2 ); +int lang_str_compare ( const lang_str_t *ls1, const lang_str_t *ls2 ); /* Empty */ int strempty(const char* c); -- 2.47.3