]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
IPTV: add icon per mux support (mainly for autonetworks)
authorJaroslav Kysela <perex@perex.cz>
Wed, 14 Oct 2015 13:27:56 +0000 (15:27 +0200)
committerJaroslav Kysela <perex@perex.cz>
Wed, 14 Oct 2015 13:27:56 +0000 (15:27 +0200)
src/channels.c
src/input/mpegts/iptv/iptv.c
src/input/mpegts/iptv/iptv_auto.c
src/input/mpegts/iptv/iptv_mux.c
src/input/mpegts/iptv/iptv_private.h
src/input/mpegts/iptv/iptv_service.c
src/input/mpegts/mpegts_service.c

index a161aff822bc66106f826393835f2fd7417a388f..be5d984d6cb60e15e2019454e4f80f460976f6bd 100644 (file)
@@ -604,12 +604,28 @@ channel_get_icon ( channel_t *ch )
   const char *chicon = config.chicon_path,
              *picon  = config.picon_path,
              *icon   = ch->ch_icon,
-             *chname;
+             *chname, *icn;
   uint32_t id, i, pick, prefer = config.prefer_picon ? 1 : 0;
 
   if (icon && *icon == '\0')
     icon = NULL;
 
+  /*
+   * Initial lookup - for services with predefined icons (like M3U sources)
+   */
+  if (icon == NULL) {
+    LIST_FOREACH(ilm, &ch->ch_services, ilm_in2_link) {
+      if (!(icn = service_get_channel_icon((service_t *)ilm->ilm_in1))) continue;
+      if (strncmp(icn, "picon://", 8) == 0) continue;
+      if (check_file(icn)) {
+        icon = ch->ch_icon = strdup(icn);
+        channel_save(ch);
+        idnode_notify_changed(&ch->ch_id);
+        goto found;
+      }
+    }
+  }
+
   /*
    * 4 iterations:
    * 0,1: try channel name or picon
@@ -679,7 +695,6 @@ channel_get_icon ( channel_t *ch )
     /* No user icon - try access from services */
     if (pick && picon) {
       LIST_FOREACH(ilm, &ch->ch_services, ilm_in2_link) {
-        const char *icn;
         if (!(icn = service_get_channel_icon((service_t *)ilm->ilm_in1))) continue;
         if (strncmp(icn, "picon://", 8))
           continue;
@@ -695,6 +710,8 @@ channel_get_icon ( channel_t *ch )
 
   }
 
+found:
+
   /* Nothing */
   if (!icon || !*icon)
     return NULL;
index 695ae8fb66c8a563e8f2c524edff85888329cc87..d152c8f17be33f784a99ac15ad64ba3ea0dbd9da 100644 (file)
@@ -482,6 +482,8 @@ iptv_network_delete ( mpegts_network_t *mn, int delconf )
   iptv_network_t *in = (iptv_network_t*)mn;
   char *url = in->in_url;
   char *sane_url = in->in_url_sane;
+  char *icon_url = in->in_icon_url;
+  char *icon_url_sane = in->in_icon_url_sane;
 
   if (in->mn_id.in_class == &iptv_auto_network_class)
     iptv_auto_network_done(in);
@@ -495,6 +497,8 @@ iptv_network_delete ( mpegts_network_t *mn, int delconf )
   free(in->in_remove_args);
   mpegts_network_delete(mn, delconf);
 
+  free(icon_url_sane);
+  free(icon_url);
   free(sane_url);
   free(url);
 }
@@ -509,6 +513,13 @@ iptv_network_class_delete ( idnode_t *in )
   return iptv_network_delete((mpegts_network_t *)in, 1);
 }
 
+static int
+iptv_network_class_icon_url_set( void *in, const void *v )
+{
+  iptv_network_t *mn = in;
+  return iptv_url_set(&mn->in_icon_url, &mn->in_icon_url_sane, v, 1, 0);
+}
+
 extern const idclass_t mpegts_network_class;
 const idclass_t iptv_network_class = {
   .ic_super      = &mpegts_network_class,
@@ -553,6 +564,14 @@ const idclass_t iptv_network_class = {
       .off      = offsetof(iptv_network_t, in_max_timeout),
       .def.i    = 15,
     },
+    {
+      .type     = PT_STR,
+      .id       = "icon_url",
+      .name     = N_("Icon base URL"),
+      .off      = offsetof(iptv_network_t, in_icon_url),
+      .set      = iptv_network_class_icon_url_set,
+      .opts     = PO_MULTILINE
+    },
     {}
   }
 };
index 0263ab2c1635c9329fd749da33f09a9f273fe116..825de463e5defbfa1d5e896722bd96a0da6e0c31 100644 (file)
 #include <fcntl.h>
 #include <sys/stat.h>
 
+/*
+ *
+ */
+static char *get_m3u_str(char *data, char **res)
+{
+  char *p = data, first = *data;
+  
+  if (first == '"' || first == '\'') {
+    data++;
+    p = data;
+    while (*data && *data != first)
+      data++;
+  } else {
+    p = data;
+    while (*data && *data != ',' && *data > ' ')
+      data++;
+  }
+  *res = data;
+  if (*data) {
+    *data = '\0';
+    (*res)++;
+  }
+  return p;
+}
+
 /*
  *
  */
@@ -33,6 +58,7 @@ iptv_auto_network_process_m3u_item(iptv_network_t *in,
                                    const char *last_url,
                                    const http_arg_list_t *remove_args,
                                    const char *url, const char *name,
+                                   const char *logo,
                                    int64_t chnum, int *total, int *count)
 {
   htsmsg_t *conf;
@@ -122,11 +148,16 @@ iptv_auto_network_process_m3u_item(iptv_network_t *in,
         im->mm_iptv_chnum = chnum;
         change = 1;
       }
-      if ((1 || im->mm_iptv_muxname == NULL || im->mm_iptv_muxname[0] == '\0') && n && *n) {
+      if ((im->mm_iptv_muxname == NULL || im->mm_iptv_muxname[0] == '\0') && n && *n) {
         free(im->mm_iptv_muxname);
         im->mm_iptv_muxname = strdup(n);
         change = 1;
       }
+      if (strcmp(im->mm_iptv_icon ?: "", logo ?: "")) {
+        free(im->mm_iptv_icon);
+        im->mm_iptv_icon = logo ? strdup(logo) : NULL;
+        change = 1;
+      }
       if (change)
         idnode_notify_changed(&im->mm_id);
       (*total)++;
@@ -161,7 +192,7 @@ iptv_auto_network_process_m3u(iptv_network_t *in, char *data,
                               http_arg_list_t *remove_args,
                               int64_t chnum)
 {
-  char *url, *name = NULL;
+  char *url, *name = NULL, *logo = NULL;
   int total = 0, count = 0;
 
   while (*data && *data != '\n') data++;
@@ -169,8 +200,20 @@ iptv_auto_network_process_m3u(iptv_network_t *in, char *data,
   while (*data) {
     if (strncmp(data, "#EXTINF:", 8) == 0) {
       name = NULL;
+      logo = NULL;
       data += 8;
-      while (*data && *data != ',') data++;
+      while (1) {
+        while (*data && *data <= ' ') data++;
+        if (*data == ',') break;
+        if (strncmp(data, "tvg-logo=", 9) == 0)
+          logo = get_m3u_str(data + 9, &data);
+        else if (strncmp(data, "logo=", 5) == 0)
+          logo = get_m3u_str(data + 5, &data);
+        else {
+          data++;
+          while (*data && *data != ',' && *data > ' ') data++;
+        }
+      }
       if (*data == ',') {
         data++;
         while (*data && *data <= ' ') data++;
@@ -186,7 +229,8 @@ iptv_auto_network_process_m3u(iptv_network_t *in, char *data,
     while (*data && *data != '\n') data++;
     if (*data) { *data = '\0'; data++; }
     if (*url)
-      iptv_auto_network_process_m3u_item(in, last_url, remove_args, url, name,
+      iptv_auto_network_process_m3u_item(in, last_url, remove_args,
+                                         url, name, logo,
                                          chnum, &total, &count);
   }
 
index 8422e8a5b6d555df06038957db9f0c7a5af92bb6..691b251e22690247b0e509e12789b055f66e9958 100644 (file)
@@ -169,6 +169,12 @@ const idclass_t iptv_mux_class =
       .name     = N_("Channel number"),
       .off      = offsetof(iptv_mux_t, mm_iptv_chnum),
     },
+    {
+      .type     = PT_STR,
+      .id       = "iptv_icon",
+      .name     = N_("Icon URL"),
+      .off      = offsetof(iptv_mux_t, mm_iptv_icon),
+    },
     {
       .type     = PT_STR,
       .id       = "iptv_sname",
@@ -240,6 +246,7 @@ iptv_mux_delete ( mpegts_mux_t *mm, int delconf )
   free(im->mm_iptv_interface);
   free(im->mm_iptv_svcname);
   free(im->mm_iptv_env);
+  free(im->mm_iptv_icon);
   mpegts_mux_delete(mm, delconf);
   free(url);
   free(url_sane);
index f1632b33122c774165d79a5e3c9ae3793e765650..3882eb2aec8cb56d52d1a83cf1046246b167e1a4 100644 (file)
@@ -85,6 +85,8 @@ struct iptv_network
   char    *in_url_sane;
   int64_t  in_channel_number;
   uint32_t in_refetch_period;
+  char    *in_icon_url;
+  char    *in_icon_url_sane;
   int      in_ssl_peer_verify;
   char    *in_remove_args;
   gtimer_t in_auto_timer;
@@ -115,6 +117,7 @@ struct iptv_mux
   char                 *mm_iptv_muxname;
   char                 *mm_iptv_svcname;
   int64_t               mm_iptv_chnum;
+  char                 *mm_iptv_icon;
 
   int                   mm_iptv_respawn;
   time_t                mm_iptv_respawn_last;
index 19e1d61e5c0f63a76642227c605dced74ee286f6..e19f813a0151566e71277a6613a4736bc620adb5 100644 (file)
@@ -77,6 +77,29 @@ iptv_service_channel_number ( service_t *s )
   return mpegts_service_channel_number(s);
 }
 
+static const char *
+iptv_service_channel_icon ( service_t *s )
+{
+  iptv_service_t   *is = (iptv_service_t *)s;
+  iptv_mux_t       *im = (iptv_mux_t *)is->s_dvb_mux;
+  iptv_network_t   *in = (iptv_network_t *)im->mm_network;
+  const char       *ic = im->mm_iptv_icon;
+  if (ic && ic[0]) {
+    if (strncmp(ic, "http://", 7) == 0 ||
+        strncmp(ic, "https://", 8) == 0)
+      return ic;
+    if (strncmp(ic, "file:///", 8) == 0)
+      return ic + 7;
+    if (strncmp(ic, "file://", 7) == 0)
+      ic += 7;
+    if (in && in->in_icon_url && in->in_icon_url[0]) {
+      snprintf(prop_sbuf, PROP_SBUF_LEN, "%s/%s", in->in_icon_url, ic + 7);
+      return prop_sbuf;
+    }
+  }
+  return NULL;
+}
+
 /*
  * Create
  */
@@ -94,6 +117,7 @@ iptv_service_create0
   is->s_delete         = iptv_service_delete;
   is->s_channel_name   = iptv_service_channel_name;
   is->s_channel_number = iptv_service_channel_number;
+  is->s_channel_icon   = iptv_service_channel_icon;
 
   /* Set default service name */
   if (!is->s_dvb_svcname || !*is->s_dvb_svcname)
index bd145dc538d8c84a2a7471628d9679b02548954f..d118037ad8fe1e105efcaf1561f94689b3e91a05 100644 (file)
@@ -497,7 +497,6 @@ mpegts_service_channel_icon ( service_t *s )
   if (ms->s_dvb_mux &&
       idnode_is_instance(&ms->s_dvb_mux->mm_id, &dvb_mux_class)) {
     int32_t hash = 0;
-    static char buf[128];
     dvb_mux_t *mmd = (dvb_mux_t*)ms->s_dvb_mux;
     int pos;
 
@@ -525,14 +524,14 @@ mpegts_service_channel_icon ( service_t *s )
         return NULL;
     }
 
-    snprintf(buf, sizeof(buf),
+    snprintf(prop_sbuf, PROP_SBUF_LEN,
              "picon://1_0_%X_%X_%X_%X_%X_0_0_0.png",
              ms->s_dvb_servicetype,
              ms->s_dvb_service_id,
              ms->s_dvb_mux->mm_tsid,
              ms->s_dvb_mux->mm_onid,
              hash);
-    return buf;
+    return prop_sbuf;
   }
 #endif