From: Jaroslav Kysela Date: Mon, 7 Mar 2016 12:48:49 +0000 (+0100) Subject: bouquets: improve mapping / tag creation, fixes #3608 X-Git-Tag: v4.2.1~949 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3b6a5ac19784bdf2c42d1de5e8ea0863c4525cec;p=thirdparty%2Ftvheadend.git bouquets: improve mapping / tag creation, fixes #3608 --- diff --git a/src/bouquet.c b/src/bouquet.c index 0a95d0337..69120f658 100644 --- a/src/bouquet.c +++ b/src/bouquet.c @@ -66,6 +66,7 @@ bouquet_create(const char *uuid, htsmsg_t *conf, bq->bq_services = idnode_set_create(1); bq->bq_active_services = idnode_set_create(1); bq->bq_ext_url_period = 60; + bq->bq_mapencrypted = 1; if (idnode_insert(&bq->bq_id, uuid, &bouquet_class, 0)) { if (uuid) @@ -273,6 +274,7 @@ bouquet_map_channel(bouquet_t *bq, service_t *t) .check_availability = 0, .encrypted = 1, .merge_same_name = 0, + .type_tags = 0, .provider_tags = 0, .network_tags = 0 }; @@ -287,12 +289,19 @@ bouquet_map_channel(bouquet_t *bq, service_t *t) return; if (!bq->bq_mapnoname && noname(service_get_channel_name(t))) return; + if (!bq->bq_mapencrypted && service_is_encrypted(t)) + return; LIST_FOREACH(ilm, &t->s_channels, ilm_in1_link) if (((channel_t *)ilm->ilm_in2)->ch_bouquet == bq) break; - if (!ilm) + if (!ilm) { + sm_conf.encrypted = bq->bq_mapencrypted; + sm_conf.merge_same_name = bq->bq_mapmergename; + sm_conf.type_tags = bq->bq_chtag_type_tags; + sm_conf.provider_tags = bq->bq_chtag_provider_tags; + sm_conf.network_tags = bq->bq_chtag_network_tags; ch = service_mapper_process(&sm_conf, t, bq); - else + } else ch = (channel_t *)ilm->ilm_in2; if (ch && bq->bq_chtag) if (channel_tag_map(bouquet_tag(bq, 1), ch, ch)) @@ -672,48 +681,68 @@ bouquet_class_maptoch_notify ( void *obj, const char *lang ) } static void -bouquet_class_mapnolcn_notify ( void *obj, const char *lang ) +bouquet_class_lcn_offset_notify ( void *obj, const char *lang ) { - bouquet_t *bq = obj; - service_t *t; - size_t z; - - if (bq->bq_in_load) + if (((bouquet_t *)obj)->bq_in_load) return; - if (!bq->bq_mapnolcn && bq->bq_enabled && bq->bq_maptoch) { - for (z = 0; z < bq->bq_services->is_count; z++) { - t = (service_t *)bq->bq_services->is_array[z]; - if ((bq->bq_only_bq_lcn || service_get_channel_number(t) <= 0) && - bouquet_get_channel_number0(bq, t) <= 0) - bouquet_unmap_channel(bq, t); - } - } else { - bouquet_map_to_channels(bq); - } + bouquet_notify_channels((bouquet_t *)obj); } -static void -bouquet_class_mapnoname_notify ( void *obj, const char *lang ) +static idnode_slist_t bouquest_class_mapopt_slist[] = { + { + .id = "mapnolcn", + .name = N_("Map zero-numbered channels"), + .off = offsetof(bouquet_t, bq_mapnolcn), + }, + { + .id = "mapnoname", + .name = N_("Map unnamed channels"), + .off = offsetof(bouquet_t, bq_mapnoname), + }, + { + .id = "mapradio", + .name = N_("Map radio channels"), + .off = offsetof(bouquet_t, bq_mapradio), + }, + { + .id = "encrypted", + .name = N_("Map encrypted services"), + .off = offsetof(bouquet_t, bq_mapencrypted), + }, + { + .id = "merge_name", + .name = N_("Merge same name"), + .off = offsetof(bouquet_t, bq_mapmergename), + }, + {} +}; + +static htsmsg_t * +bouquet_class_mapopt_enum ( void *obj, const char *lang ) { - bouquet_t *bq = obj; - service_t *t; - size_t z; + return idnode_slist_enum(obj, bouquest_class_mapopt_slist, lang); +} - if (bq->bq_in_load) - return; - if (!bq->bq_mapnoname && bq->bq_enabled && bq->bq_maptoch) { - for (z = 0; z < bq->bq_services->is_count; z++) { - t = (service_t *)bq->bq_services->is_array[z]; - if (noname(service_get_channel_name(t))) - bouquet_unmap_channel(bq, t); - } - } else { - bouquet_map_to_channels(bq); - } +static const void * +bouquet_class_mapopt_get ( void *obj ) +{ + return idnode_slist_get(obj, bouquest_class_mapopt_slist); +} + +static char * +bouquet_class_mapopt_rend ( void *obj, const char *lang ) +{ + return idnode_slist_rend(obj, bouquest_class_mapopt_slist, lang); +} + +static int +bouquet_class_mapopt_set ( void *obj, const void *p ) +{ + return idnode_slist_set(obj, bouquest_class_mapopt_slist, p); } static void -bouquet_class_mapradio_notify ( void *obj, const char *lang ) +bouquet_class_mapopt_notify ( void *obj, const char *lang ) { bouquet_t *bq = obj; service_t *t; @@ -721,15 +750,68 @@ bouquet_class_mapradio_notify ( void *obj, const char *lang ) if (bq->bq_in_load) return; - if (!bq->bq_mapradio && bq->bq_enabled && bq->bq_maptoch) { + if (bq->bq_enabled && bq->bq_maptoch) { for (z = 0; z < bq->bq_services->is_count; z++) { t = (service_t *)bq->bq_services->is_array[z]; - if (service_is_radio(t)) + if (!bq->bq_mapradio && service_is_radio(t)) + bouquet_unmap_channel(bq, t); + else if (!bq->bq_mapnoname && noname(service_get_channel_name(t))) + bouquet_unmap_channel(bq, t); + else if (!bq->bq_mapradio && service_is_radio(t)) + bouquet_unmap_channel(bq, t); + else if (!bq->bq_mapencrypted && service_is_encrypted(t)) bouquet_unmap_channel(bq, t); } - } else { - bouquet_map_to_channels(bq); } + bouquet_map_to_channels(bq); +} + +static idnode_slist_t bouquest_class_chtag_slist[] = { + { + .id = "bouquet_tag", + .name = N_("Create bouquet tag"), + .off = offsetof(bouquet_t, bq_chtag), + }, + { + .id = "type_tags", + .name = N_("Create type based tags"), + .off = offsetof(bouquet_t, bq_chtag_type_tags), + }, + { + .id = "providers_tags", + .name = N_("Create provider name tags"), + .off = offsetof(bouquet_t, bq_chtag_provider_tags), + }, + { + .id = "network_tags", + .name = N_("Create network name tags"), + .off = offsetof(bouquet_t, bq_chtag_network_tags), + }, + {} +}; + +static htsmsg_t * +bouquet_class_chtag_enum ( void *obj, const char *lang ) +{ + return idnode_slist_enum(obj, bouquest_class_chtag_slist, lang); +} + +static const void * +bouquet_class_chtag_get ( void *obj ) +{ + return idnode_slist_get(obj, bouquest_class_chtag_slist); +} + +static char * +bouquet_class_chtag_rend ( void *obj, const char *lang ) +{ + return idnode_slist_rend(obj, bouquest_class_chtag_slist, lang); +} + +static int +bouquet_class_chtag_set ( void *obj, const void *p ) +{ + return idnode_slist_set(obj, bouquest_class_chtag_slist, p); } static void @@ -755,17 +837,8 @@ bouquet_class_chtag_notify ( void *obj, const char *lang ) if (ilm) channel_tag_unmap((channel_t *)ilm->ilm_in2, ct); } - } else { - bouquet_map_to_channels(bq); } -} - -static void -bouquet_class_lcn_offset_notify ( void *obj, const char *lang ) -{ - if (((bouquet_t *)obj)->bq_in_load) - return; - bouquet_notify_channels((bouquet_t *)obj); + bouquet_map_to_channels(bq); } static const void * @@ -899,36 +972,28 @@ const idclass_t bouquet_class = { .notify = bouquet_class_maptoch_notify, }, { - .type = PT_BOOL, - .id = "mapnolcn", - .name = N_("Map zero-numbered channels"), - .off = offsetof(bouquet_t, bq_mapnolcn), - .notify = bouquet_class_mapnolcn_notify, - .opts = PO_ADVANCED, - }, - { - .type = PT_BOOL, - .id = "mapnoname", - .name = N_("Map unnamed channels"), - .off = offsetof(bouquet_t, bq_mapnoname), - .notify = bouquet_class_mapnoname_notify, + .type = PT_INT, + .id = "mapopt", + .name = N_("Channel mapping options"), + .notify = bouquet_class_mapopt_notify, + .list = bouquet_class_mapopt_enum, + .get = bouquet_class_mapopt_get, + .set = bouquet_class_mapopt_set, + .rend = bouquet_class_mapopt_rend, .opts = PO_ADVANCED, + .islist = 1 }, { - .type = PT_BOOL, - .id = "mapradio", - .name = N_("Map radio channels"), - .off = offsetof(bouquet_t, bq_mapradio), - .notify = bouquet_class_mapradio_notify, - .opts = PO_ADVANCED, - }, - { - .type = PT_BOOL, + .type = PT_INT, .id = "chtag", - .name = N_("Create tag"), - .off = offsetof(bouquet_t, bq_chtag), + .name = N_("Create tags"), .notify = bouquet_class_chtag_notify, + .list = bouquet_class_chtag_enum, + .get = bouquet_class_chtag_get, + .set = bouquet_class_chtag_set, + .rend = bouquet_class_chtag_rend, .opts = PO_ADVANCED, + .islist = 1 }, { .type = PT_STR, diff --git a/src/bouquet.h b/src/bouquet.h index 1cf3eb9c2..638e98db6 100644 --- a/src/bouquet.h +++ b/src/bouquet.h @@ -40,7 +40,12 @@ typedef struct bouquet { int bq_mapnolcn; int bq_mapnoname; int bq_mapradio; + int bq_mapencrypted; + int bq_mapmergename; int bq_chtag; + int bq_chtag_type_tags; + int bq_chtag_provider_tags; + int bq_chtag_network_tags; channel_tag_t*bq_chtag_ptr; const char *bq_chtag_waiting; char *bq_name; diff --git a/src/idnode.c b/src/idnode.c index 5d094db5a..37ede547c 100644 --- a/src/idnode.c +++ b/src/idnode.c @@ -1393,6 +1393,87 @@ idnode_serialize0(idnode_t *self, htsmsg_t *list, int optmask, const char *lang) return m; } +/* ************************************************************************** + * Simple list helpers + * *************************************************************************/ + +htsmsg_t * +idnode_slist_enum ( idnode_t *in, idnode_slist_t *options, const char *lang ) +{ + htsmsg_t *l = htsmsg_create_list(), *m; + + for (; options->id; options++) { + m = htsmsg_create_map(); + htsmsg_add_str(m, "key", options->id); + htsmsg_add_str(m, "val", tvh_gettext_lang(lang, options->name)); + htsmsg_add_msg(l, NULL, m); + } + return l; +} + +htsmsg_t * +idnode_slist_get ( idnode_t *in, idnode_slist_t *options ) +{ + htsmsg_t *l = htsmsg_create_list(); + int *ip; + + for (; options->id; options++) { + ip = (void *)in + options->off; + if (*ip) + htsmsg_add_str(l, NULL, options->id); + } + return l; +} + +int +idnode_slist_set ( idnode_t *in, idnode_slist_t *options, const htsmsg_t *vals ) +{ + idnode_slist_t *o; + htsmsg_field_t *f; + int *ip, changed = 0; + const char *s; + + for (o = options; o->id; o++) { + ip = (void *)in + o->off; + HTSMSG_FOREACH(f, vals) { + if ((s = htsmsg_field_get_str(f)) != NULL) + continue; + if (strcmp(s, o->id)) + continue; + if (*ip == 0) changed = 1; + break; + } + if (f == NULL && *ip) changed = 1; + } + HTSMSG_FOREACH(f, vals) { + if ((s = htsmsg_field_get_str(f)) != NULL) + continue; + for (o = options; o->id; o++) { + if (strcmp(o->id, s)) continue; + ip = (void *)in + o->off; + *ip = 1; + break; + } + } + return changed; +} + +char * +idnode_slist_rend ( idnode_t *in, idnode_slist_t *options, const char *lang ) +{ + int *ip; + size_t l = 0; + + prop_sbuf[0] = '\0'; + for (; options->id; options++) { + ip = (void *)in + options->off; + if (*ip) + tvh_strlcatf(prop_sbuf, PROP_SBUF_LEN, l, "%s%s", prop_sbuf[0] ? "," : "", + tvh_gettext_lang(lang, options->name)); + } + return prop_sbuf_ptr; +} + /* ************************************************************************** * List helpers * *************************************************************************/ diff --git a/src/idnode.h b/src/idnode.h index 3c4f00d31..380cfc850 100644 --- a/src/idnode.h +++ b/src/idnode.h @@ -110,6 +110,15 @@ struct idnode_save { int64_t ise_reqtime; ///< First request }; +/* + * Simple list + */ +typedef struct idnode_slist { + const char *id; + const char *name; + size_t off; +} idnode_slist_t; + /* * Node list mapping definition */ @@ -235,6 +244,11 @@ static inline void idnode_perm_unset(idnode_t *self) { self->in_access = NULL; } (((idnode_t *)self)->in_access ? \ ((idnode_t *)self)->in_access->aa_lang_ui : NULL) +htsmsg_t * idnode_slist_enum ( idnode_t *in, idnode_slist_t *options, const char *lang ); +htsmsg_t * idnode_slist_get ( idnode_t *in, idnode_slist_t *options ); +int idnode_slist_set ( idnode_t *in, idnode_slist_t *options, const htsmsg_t *vals ); +char * idnode_slist_rend ( idnode_t *in, idnode_slist_t *options, const char *lang ); + idnode_list_mapping_t * idnode_list_link ( idnode_t *in1, idnode_list_head_t *in1_list, idnode_t *in2, idnode_list_head_t *in2_list, diff --git a/src/webui/static/app/cteditor.js b/src/webui/static/app/cteditor.js index 0d7a3de70..1cb89552d 100644 --- a/src/webui/static/app/cteditor.js +++ b/src/webui/static/app/cteditor.js @@ -33,8 +33,7 @@ tvheadend.cteditor = function(panel, index) */ tvheadend.bouquet = function(panel, index) { - var list0 = 'name,maptoch,mapnolcn,lcn_off,mapnoname,mapradio,' + - 'chtag,source,services_count,services_seen,comment'; + var list0 = 'name,maptoch,lcn_off,mapopt,chtag,source,services_count,services_seen,comment'; var list = 'enabled,rescan,' + list0; var elist = 'enabled,rescan,ext_url,' + list0; var alist = 'enabled,ext_url,' + list0; @@ -49,12 +48,9 @@ tvheadend.bouquet = function(panel, index) enabled: { width: 50 }, rescan: { width: 50 }, name: { width: 200 }, - maptoch: { width: 100 }, - mapnolcn: { width: 100 }, - mapradio: { width: 100 }, lcn_off: { width: 100 }, - mapnoname: { width: 100 }, - chtag: { width: 100 }, + mapopt: { width: 150 }, + chtag: { width: 150 }, source: { width: 200 }, services_count: { width: 100 }, services_seen: { width: 100 },