]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
bouquets: improve mapping / tag creation, fixes #3608
authorJaroslav Kysela <perex@perex.cz>
Mon, 7 Mar 2016 12:48:49 +0000 (13:48 +0100)
committerJaroslav Kysela <perex@perex.cz>
Mon, 7 Mar 2016 12:48:49 +0000 (13:48 +0100)
src/bouquet.c
src/bouquet.h
src/idnode.c
src/idnode.h
src/webui/static/app/cteditor.js

index 0a95d0337a357d7f414d219f9540d21398f7e1f4..69120f658c12168fae907dc98d87cb97b9091f30 100644 (file)
@@ -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,
index 1cf3eb9c2c76f9efac824e321c21e99bcf4712f5..638e98db68a697a0cbb75a9eb10f4ad39c9a84a7 100644 (file)
@@ -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;
index 5d094db5ab55bac18844bc250538705014e20e5f..37ede547c1f02eaa69cd4dd9a578080f6424cba9 100644 (file)
@@ -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
  * *************************************************************************/
index 3c4f00d3126f35a0377f2e761cc08cf3a235d50f..380cfc85083e918db56a52d60b1711b94f7654fd 100644 (file)
@@ -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,
index 0d7a3de702567bd7f02ad6339128afc3f52520a5..1cb89552d50e87e97b0f5f63d16be7f6ea32445a 100644 (file)
@@ -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 },