From: Jaroslav Kysela Date: Mon, 26 Oct 2015 08:26:45 +0000 (+0100) Subject: epggrab: manage multiple channel names for 'Auto EPG', fixes #3205 X-Git-Tag: v4.2.1~1772 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=eda1d0d76a70ce83a73a690a895a1447e8cb895e;p=thirdparty%2Ftvheadend.git epggrab: manage multiple channel names for 'Auto EPG', fixes #3205 --- diff --git a/src/epggrab.h b/src/epggrab.h index b8327f2df..db91bb145 100644 --- a/src/epggrab.h +++ b/src/epggrab.h @@ -88,6 +88,8 @@ typedef struct epggrab_channel char *id; ///< Grabber's ID char *name; ///< Channel name + htsmsg_t *names; ///< List of all channel names for grabber's ID + htsmsg_t *newnames;///< List of all channel names for grabber's ID (scan) char *icon; ///< Channel icon char *comment; ///< Channel comment (EPG) int64_t lcn; ///< Channel number (split) diff --git a/src/epggrab/channel.c b/src/epggrab/channel.c index 3c5feffbe..feb892436 100644 --- a/src/epggrab/channel.c +++ b/src/epggrab/channel.c @@ -39,10 +39,18 @@ SKEL_DECLARE(epggrab_channel_skel, epggrab_channel_t); /* Check if channels match */ int epggrab_channel_match ( epggrab_channel_t *ec, channel_t *ch ) { + const char *chid, *s; + htsmsg_field_t *f; + if (!ec || !ch || !ch->ch_epgauto || !ch->ch_enabled || !ec->enabled) return 0; if (LIST_FIRST(&ec->channels)) return 0; // ignore already paired - if (ec->name && !strcmp(ec->name, channel_get_epgid(ch))) return 1; + chid = channel_get_epgid(ch); + if (ec->name && !strcmp(ec->name, chid)) return 1; + if (ec->names) + HTSMSG_FOREACH(f, ec->names) + if ((s = htsmsg_field_get_str(f)) != NULL) + if (!strcmp(s, chid)) return 1; if (ec->lcn && ec->lcn == channel_get_number(ch)) return 1; return 0; } @@ -127,7 +135,7 @@ int epggrab_channel_set_name ( epggrab_channel_t *ec, const char *name ) channel_t *ch; int save = 0; if (!ec || !name) return 0; - if (!ec->name || strcmp(ec->name, name)) { + if (!ec->newnames && (!ec->name || strcmp(ec->name, name))) { if (ec->name) free(ec->name); ec->name = strdup(name); if (epggrab_conf.channel_rename) { @@ -139,6 +147,9 @@ int epggrab_channel_set_name ( epggrab_channel_t *ec, const char *name ) } save = 1; } + if (ec->newnames == NULL) + ec->newnames = htsmsg_create_list(); + htsmsg_add_str(ec->newnames, NULL, name); return save; } @@ -304,6 +315,8 @@ void epggrab_channel_destroy( epggrab_channel_t *ec, int delconf ) hts_settings_remove("epggrab/%s/channels/%s", ec->mod->saveid, idnode_uuid_as_sstr(&ec->idnode)); + htsmsg_destroy(ec->newnames); + htsmsg_destroy(ec->names); free(ec->comment); free(ec->name); free(ec->icon); @@ -319,6 +332,29 @@ void epggrab_channel_flush epggrab_channel_destroy(ec, delconf); } +void epggrab_channel_begin_scan ( epggrab_module_t *mod ) +{ + epggrab_channel_t *ec; + lock_assert(&global_lock); + RB_FOREACH(ec, &mod->channels, link) + if (ec->newnames) { + htsmsg_destroy(ec->newnames); + ec->newnames = NULL; + } +} + +void epggrab_channel_end_scan ( epggrab_module_t *mod ) +{ + epggrab_channel_t *ec; + lock_assert(&global_lock); + RB_FOREACH(ec, &mod->channels, link) + if (ec->newnames) { + htsmsg_destroy(ec->names); + ec->names = ec->newnames; + ec->newnames = NULL; + } +} + /* ************************************************************************** * Global routines * *************************************************************************/ @@ -435,6 +471,30 @@ epggrab_channel_class_path_get ( void *obj ) return &prop_sbuf_ptr; } +static const void * +epggrab_channel_class_names_get ( void *obj ) +{ + epggrab_channel_t *ec = obj; + char *s = ec->names ? htsmsg_list_2_csv(ec->names, ',', 0) : NULL; + snprintf(prop_sbuf, PROP_SBUF_LEN, "%s", s ?: ""); + free(s); + return &prop_sbuf_ptr; +} + +static int +epggrab_channel_class_names_set ( void *obj, const void *p ) +{ + htsmsg_t *m = htsmsg_csv_2_list(p, ','); + epggrab_channel_t *ec = obj; + if (htsmsg_cmp(ec->names, m)) { + htsmsg_destroy(ec->names); + ec->names = m; + } else { + htsmsg_destroy(m); + } + return 0; +} + static const void * epggrab_channel_class_channels_get ( void *obj ) { @@ -508,6 +568,13 @@ const idclass_t epggrab_channel_class = { .name = N_("Name"), .off = offsetof(epggrab_channel_t, name), }, + { + .type = PT_STR, + .id = "names", + .name = N_("Names"), + .get = epggrab_channel_class_names_get, + .set = epggrab_channel_class_names_set, + }, { .type = PT_S64, .intsplit = CHANNEL_SPLIT, diff --git a/src/epggrab/module/pyepg.c b/src/epggrab/module/pyepg.c index 3f5d5cb96..a606a1aed 100644 --- a/src/epggrab/module/pyepg.c +++ b/src/epggrab/module/pyepg.c @@ -373,6 +373,10 @@ static int _pyepg_parse_epg if ((tags = htsmsg_get_map(data, "tags")) == NULL) return 0; + pthread_mutex_lock(&global_lock); + epggrab_channel_begin_scan(mod); + pthread_mutex_unlock(&global_lock); + HTSMSG_FOREACH(f, tags) { save = 0; if (strcmp(f->hmf_name, "channel") == 0 ) { @@ -403,6 +407,10 @@ static int _pyepg_parse_epg gsave |= save; } + pthread_mutex_lock(&global_lock); + epggrab_channel_end_scan(mod); + pthread_mutex_unlock(&global_lock); + return gsave; } diff --git a/src/epggrab/module/xmltv.c b/src/epggrab/module/xmltv.c index 04f28de10..f8b00f7cd 100644 --- a/src/epggrab/module/xmltv.c +++ b/src/epggrab/module/xmltv.c @@ -651,6 +651,10 @@ static int _xmltv_parse_tv if((tags = htsmsg_get_map(body, "tags")) == NULL) return 0; + pthread_mutex_lock(&global_lock); + epggrab_channel_begin_scan(mod); + pthread_mutex_unlock(&global_lock); + HTSMSG_FOREACH(f, tags) { save = 0; if(!strcmp(f->hmf_name, "channel")) { @@ -665,6 +669,11 @@ static int _xmltv_parse_tv } gsave |= save; } + + pthread_mutex_lock(&global_lock); + epggrab_channel_end_scan(mod); + pthread_mutex_unlock(&global_lock); + return gsave; } diff --git a/src/epggrab/private.h b/src/epggrab/private.h index 970043b85..0fa93d73b 100644 --- a/src/epggrab/private.h +++ b/src/epggrab/private.h @@ -61,6 +61,10 @@ void epggrab_channel_destroy ( epggrab_channel_t *ec, int delconf ); void epggrab_channel_flush ( epggrab_module_t *mod, int delconf ); +void epggrab_channel_begin_scan + ( epggrab_module_t *mod ); +void epggrab_channel_end_scan + ( epggrab_module_t *mod ); void epggrab_channel_init(void); void epggrab_channel_done(void); diff --git a/src/htsmsg.c b/src/htsmsg.c index 792f99ab8..0c89f7a46 100644 --- a/src/htsmsg.c +++ b/src/htsmsg.c @@ -937,6 +937,71 @@ htsmsg_copy(htsmsg_t *src) return dst; } +/** + * + */ +int +htsmsg_cmp(htsmsg_t *m1, htsmsg_t *m2) +{ + htsmsg_field_t *f1, *f2; + + if (m1 == NULL && m2 == NULL) + return 0; + if (m1 == NULL || m2 == NULL) + return 1; + + f2 = TAILQ_FIRST(&m2->hm_fields); + TAILQ_FOREACH(f1, &m1->hm_fields, hmf_link) { + + if (f1->hmf_type != f2->hmf_type) + return 1; + if (strcmp(f1->hmf_name ?: "", f2->hmf_name ?: "")) + return 1; + + switch(f1->hmf_type) { + + case HMF_MAP: + case HMF_LIST: + if (htsmsg_cmp(&f1->hmf_msg, &f2->hmf_msg)) + return 1; + break; + + case HMF_STR: + if (strcmp(f1->hmf_str, f2->hmf_str)) + return 1; + break; + + case HMF_S64: + if (f1->hmf_s64 != f2->hmf_s64) + return 1; + break; + + case HMF_BOOL: + if (f1->hmf_bool != f2->hmf_bool) + return 1; + break; + + case HMF_BIN: + if (f1->hmf_binsize != f2->hmf_binsize) + return 1; + if (memcmp(f1->hmf_bin, f2->hmf_bin, f1->hmf_binsize)) + return 1; + break; + + case HMF_DBL: + if (f1->hmf_dbl != f2->hmf_dbl) + return 1; + break; + } + + f2 = TAILQ_NEXT(f2, hmf_link); + } + + if (f2) + return 1; + return 0; +} + /** * */ @@ -1004,12 +1069,11 @@ htsmsg_list_2_csv(htsmsg_t *m, char delim, int human) if (human) { sep[0] = delim; sep[1] = ' '; - sep[2] = '\0'; - ssep = "\""; + ssep = ""; } else { sep[0] = delim; sep[1] = '\0'; - ssep = ""; + ssep = "\""; } HTSMSG_FOREACH(f, m) { if (f->hmf_type == HMF_STR) { diff --git a/src/htsmsg.h b/src/htsmsg.h index 334cfc601..78fcf8e78 100644 --- a/src/htsmsg.h +++ b/src/htsmsg.h @@ -389,6 +389,11 @@ htsmsg_field_t *htsmsg_field_last(htsmsg_t *msg); */ htsmsg_t *htsmsg_copy(htsmsg_t *src); +/** + * Compare a message. + */ +int htsmsg_cmp(htsmsg_t *m1, htsmsg_t *m2); + #define HTSMSG_FOREACH(f, msg) TAILQ_FOREACH(f, &(msg)->hm_fields, hmf_link)