]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
[PR-174] - Replaced user submitted icon cache with more generic image cache.
authorAdam Sutton <dev@adamsutton.me.uk>
Sun, 30 Dec 2012 20:09:27 +0000 (20:09 +0000)
committerAdam Sutton <dev@adamsutton.me.uk>
Tue, 1 Jan 2013 09:30:28 +0000 (09:30 +0000)
This allows file:// paths to be specified for channel icons even if image
cache support is disabled.

The image cache functionality is compile time optional (for those without
curl support) and also run-time configurable for those that don't want it.

All images, including EPG ones should be cached.

18 files changed:
Makefile
configure
src/channels.c
src/config2.c
src/config2.h
src/epg.c
src/htsp_server.c
src/iconserve.c [deleted file]
src/iconserve.h [deleted file]
src/imagecache.c [new file with mode: 0644]
src/imagecache.h [new file with mode: 0644]
src/main.c
src/settings.c
src/settings.h
src/webui/extjs.c
src/webui/statedump.c
src/webui/static/app/config.js
src/webui/webui.c

index c63cbe5873e9198f86cfdb27c329a5c67a169414..63629f4a36a813002fb500a47aaaace6fb6db475 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -32,7 +32,7 @@ CFLAGS  += -Wmissing-prototypes -fms-extensions
 CFLAGS  += -g -funsigned-char -O2 
 CFLAGS  += -D_FILE_OFFSET_BITS=64
 CFLAGS  += -I${BUILDDIR} -I${CURDIR}/src -I${CURDIR}
-LDFLAGS += -lrt -ldl -lpthread -lm -lcurl
+LDFLAGS += -lrt -ldl -lpthread -lm
 
 #
 # Other config
@@ -109,6 +109,7 @@ SRCS =  src/main.c \
   src/config2.c \
   src/lang_codes.c \
   src/lang_str.c \
+  src/imagecache.c
 
 SRCS += src/epggrab/module.c\
   src/epggrab/channel.c\
@@ -140,8 +141,6 @@ SRCS += src/muxer.c \
        src/muxer_pass.c \
        src/muxer_tvh.c \
 
-SRCS += src/iconserve.c \
-
 #
 # Optional code
 #
index 8e02c1b438dc4311c8e1ccc03dbc231f20899fa6..765a98987818e28e8bb9f5c7e33a4abd7e407f57 100755 (executable)
--- a/configure
+++ b/configure
@@ -20,6 +20,7 @@ OPTIONS=(
   "v4l:yes"
   "linuxdvb:yes"
   "dvbscan:yes"
+  "imagecache:auto"
   "avahi:auto"
   "zlib:auto"
   "bundle:no"
@@ -126,7 +127,17 @@ if enabled cwc && enabled dvbcsa; then
   die "Failed to find dvbcsa support (use --disable-dvbcsa)"
   LDFLAGS="$LDFLAGS -ldvbcsa"
 fi
-  
+
+#
+# Icon caching
+#
+if enabled_or_auto imagecache; then
+  if check_pkg libcurl; then
+    enable imagecache
+  elif enabled imagecache; then
+    die "Libcurl support not found (use --disable-imagecache)"
+  fi  
+fi
 
 # ###########################################################################
 # Write config
index 7c8112eca52ea93c4e25daa3054cf835db0ffc19..970da8e64a432dbebc4d493f7a4e32d66c89de37 100644 (file)
@@ -39,6 +39,7 @@
 #include "notify.h"
 #include "dvr/dvr.h"
 #include "htsp_server.h"
+#include "imagecache.h"
 
 struct channel_tree channel_name_tree;
 static struct channel_tree channel_identifier_tree;
@@ -268,6 +269,7 @@ channel_load_one(htsmsg_t *c, int id)
   epggrab_channel_add(ch);
 
   tvh_str_update(&ch->ch_icon, htsmsg_get_str(c, "icon"));
+  imagecache_get_id(ch->ch_icon);
 
   htsmsg_get_s32(c, "dvr_extra_time_pre",  &ch->ch_dvr_extra_time_pre);
   htsmsg_get_s32(c, "dvr_extra_time_post", &ch->ch_dvr_extra_time_post);
@@ -452,6 +454,7 @@ channel_set_icon(channel_t *ch, const char *icon)
 
   free(ch->ch_icon);
   ch->ch_icon = strdup(icon);
+  imagecache_get_id(icon);
   channel_save(ch);
   htsp_channel_update(ch);
 }
index b90db4fed1586ee51e47cc881f819df2be0a2f34..5bcbd0d1a02a00334fb913fe0f310147564708b3 100644 (file)
@@ -74,50 +74,3 @@ int config_set_muxconfpath ( const char *path )
   }
   return 0;
 }
-
-const char *config_get_iconserve ( void )
-{
-  return htsmsg_get_str(config, "iconserve");
-}
-
-int config_set_iconserve ( const char *setting )
-{
-  const char *c = config_get_iconserve(); 
-  if (!c || strcmp(c, setting)) {
-    if (c) htsmsg_delete_field(config, "iconserve");
-    htsmsg_add_str(config, "iconserve", setting);
-    return 1;
-  }
-  return 0;
-}
-const char *config_get_iconserve_periodicdownload ( void )
-{
-  return htsmsg_get_str(config, "iconserve_periodicdownload");
-}
-
-int config_set_iconserve_periodicdownload ( const char *setting )
-{
-  const char *c = config_get_iconserve_periodicdownload(); 
-  if (!c || strcmp(c, setting)) {
-    if (c) htsmsg_delete_field(config, "iconserve_periodicdownload");
-    htsmsg_add_str(config, "iconserve_periodicdownload", setting);
-    return 1;
-  }
-  return 0;
-}
-
-const char *config_get_serverip ( void )
-{
-  return htsmsg_get_str(config, "serverip");
-};
-
-int config_set_serverip ( const char *setting )
-{
-  const char *c = config_get_serverip(); 
-  if (!c || strcmp(c, setting)) {
-    if (c) htsmsg_delete_field(config, "serverip");
-    htsmsg_add_str(config, "serverip", setting);
-    return 1;
-  }
-  return 0;
-};
index 6e90be6fae15a817f27aa3ecfbbd272269a7a7e5..cd68e30621de19e679970fe49ed61f49708c6e60 100644 (file)
@@ -32,18 +32,6 @@ const char *config_get_muxconfpath ( void );
 int         config_set_muxconfpath ( const char *str )
   __attribute__((warn_unused_result));
 
-const char *config_get_iconserve ( void );
-int         config_set_iconserve ( const char *str )
-  __attribute__((warn_unused_result));
-
-const char *config_get_iconserve_periodicdownload ( void );
-int         config_set_iconserve_periodicdownload ( const char *str )
-  __attribute__((warn_unused_result));
-
-const char *config_get_serverip ( void );
-int         config_set_serverip ( const char *str )
-  __attribute__((warn_unused_result));
-
 const char *config_get_language    ( void );
 int         config_set_language    ( const char *str )
   __attribute__((warn_unused_result));
index fafb65ddb833f737918266eeac804e4c4323638d..6984fa0e4f691bd9fb7bfe7fef94adf40e7e838c 100644 (file)
--- a/src/epg.c
+++ b/src/epg.c
@@ -32,6 +32,7 @@
 #include "dvr/dvr.h"
 #include "htsp_server.h"
 #include "epggrab.h"
+#include "imagecache.h"
 
 /* Broadcast hashing */
 #define EPG_HASH_WIDTH 1024
@@ -459,8 +460,12 @@ int epg_brand_set_summary
 int epg_brand_set_image
   ( epg_brand_t *brand, const char *image, epggrab_module_t *src )
 {
+  int save;
   if (!brand || !image) return 0;
-  return _epg_object_set_str(brand, &brand->image, image, src);
+  save = _epg_object_set_str(brand, &brand->image, image, src);
+  if (save)
+    imagecache_get_id(image);
+  return save;
 }
 
 int epg_brand_set_season_count
@@ -628,8 +633,12 @@ int epg_season_set_summary
 int epg_season_set_image
   ( epg_season_t *season, const char *image, epggrab_module_t *src )
 {
+  int save;
   if (!season || !image) return 0;
-  return _epg_object_set_str(season, &season->image, image, src);
+  save = _epg_object_set_str(season, &season->image, image, src);
+  if (save)
+    imagecache_get_id(image);
+  return save;
 }
 
 int epg_season_set_episode_count
@@ -891,8 +900,12 @@ int epg_episode_set_description
 int epg_episode_set_image
   ( epg_episode_t *episode, const char *image, epggrab_module_t *src )
 {
+  int save;
   if (!episode || !image) return 0;
-  return _epg_object_set_str(episode, &episode->image, image, src);
+  save = _epg_object_set_str(episode, &episode->image, image, src);
+  if (save)
+    imagecache_get_id(image);
+  return save;
 }
 
 int epg_episode_set_number
index ba10139a8a69816b0e49611990a512c6795c07e5..243ff77e2af11d4dfd1a1c3142926fcfbf21820b 100644 (file)
@@ -42,8 +42,7 @@
 #include "htsmsg_binary.h"
 #include "epg.h"
 #include "plumbing/tsfix.h"
-#include "iconserve.h"
-#include "config2.h"
+#include "imagecache.h"
 
 #include <sys/statvfs.h>
 #include "settings.h"
@@ -434,7 +433,7 @@ htsp_file_destroy(htsp_file_t *hf)
  *
  */
 static htsmsg_t *
-htsp_build_channel(channel_t *ch, const char *method)
+htsp_build_channel(channel_t *ch, const char *method, htsp_connection_t *htsp)
 {
   channel_tag_mapping_t *ctm;
   channel_tag_t *ct;
@@ -449,10 +448,26 @@ htsp_build_channel(channel_t *ch, const char *method)
   htsmsg_add_u32(out, "channelNumber", ch->ch_number);
 
   htsmsg_add_str(out, "channelName", ch->ch_name);
-
   if(ch->ch_icon != NULL) {
-    htsmsg_add_str(out, "channelIcon", logo_query(ch->ch_id, ch->ch_icon));
-  };
+    uint32_t id = imagecache_get_id(ch->ch_icon);
+    if (id) {
+      size_t p = 0;
+      char url[256];
+      if (htsp->htsp_version <= 7) {
+        strcpy(url, "http://");
+        p = 7;
+        inet_ntop(AF_INET, &(htsp->htsp_peer->sin_addr), url+p, sizeof(url)-p);
+        p = strlen(url);
+        p += snprintf(url+p, sizeof(url)-p, ":%hd", webui_port);
+      }
+      if (tvheadend_webroot)
+        p += snprintf(url+p, sizeof(url)-p, "%s", tvheadend_webroot);
+      snprintf(url+p, sizeof(url)-p, "/imagecache/%d", id);
+      htsmsg_add_str(out, "channelIcon", url);
+    } else {
+      htsmsg_add_str(out, "channelIcon", ch->ch_icon);
+    }
+  }
 
   now  = ch->ch_epg_now;
   next = ch->ch_epg_next;
@@ -802,7 +817,7 @@ htsp_method_async(htsp_connection_t *htsp, htsmsg_t *in)
   
   /* Send all channels */
   RB_FOREACH(ch, &channel_name_tree, ch_name_link)
-    htsp_send_message(htsp, htsp_build_channel(ch, "channelAdd"), NULL);
+    htsp_send_message(htsp, htsp_build_channel(ch, "channelAdd", htsp), NULL);
     
   /* Send all enabled and external tags (now with channel mappings) */
   TAILQ_FOREACH(ct, &channel_tags, ct_link)
@@ -1880,23 +1895,30 @@ htsp_channel_update_current(channel_t *ch)
 /**
  * Called from channel.c when a new channel is created
  */
+static void
+_htsp_channel_update(channel_t *ch, const char *msg)
+{
+  htsp_connection_t *htsp;
+  LIST_FOREACH(htsp, &htsp_async_connections, htsp_async_link)
+    if (htsp->htsp_async_mode & HTSP_ASYNC_ON)
+      htsp_send_message(htsp, htsp_build_channel(ch, msg, htsp), NULL);
+}
+
 void
 htsp_channel_add(channel_t *ch)
 {
-  htsp_async_send(htsp_build_channel(ch, "channelAdd"), HTSP_ASYNC_ON);
+  _htsp_channel_update(ch, "channelAdd");
 }
 
-
 /**
  * Called from channel.c when a channel is updated
  */
 void
 htsp_channel_update(channel_t *ch)
 {
-  htsp_async_send(htsp_build_channel(ch, "channelUpdate"), HTSP_ASYNC_ON);
+  _htsp_channel_update(ch, "channelUpdate");
 }
 
-
 /**
  * Called from channel.c when a channel is deleted
  */
diff --git a/src/iconserve.c b/src/iconserve.c
deleted file mode 100644 (file)
index 85f0fe0..0000000
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- *  Icon file server operations
- *  Copyright (C) 2012 Andy Brown
- *
- *  This program is free software: you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation, either version 3 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#define CURL_STATICLIB
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <curl/curl.h>
-#include <curl/easy.h>
-#include <unistd.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <time.h>
-
-#include "settings.h"
-#include "tvheadend.h"
-#include "channels.h"
-#include "http.h"
-#include "webui/webui.h"
-#include "filebundle.h"
-#include "iconserve.h"
-#include "config2.h"
-#include "queue.h"
-#include "spawn.h"
-
-/* Queue, Cond to signal data and Mutex to protect it */
-static TAILQ_HEAD(,iconserve_grab_queue) iconserve_queue;
-static pthread_mutex_t                   iconserve_mutex;
-static pthread_cond_t                    iconserve_cond;
-
-/**
- * https://github.com/andyb2000 Function to provide local icon files
- */
-int
-page_logo(http_connection_t *hc, const char *remain, void *opaque)
-{
-  const char *homedir = hts_settings_get_root();
-  channel_t *ch = NULL;
-  char *inpath, *inpath2;
-  const char *outpath = "none";
-  char homepath[254];
-  char iconpath[100];
-  pthread_mutex_lock(&global_lock);
-  fb_file *fp;
-  ssize_t size;
-  char buf[4096];
-  char       *mimetest_outbuf;
-
-  if(remain == NULL) {
-    pthread_mutex_unlock(&global_lock);
-    return 404;
-  };
-
-  if(strstr(remain, "..")) {
-    pthread_mutex_unlock(&global_lock);
-    return HTTP_STATUS_BAD_REQUEST;
-  };
-
-  ch = channel_find_by_identifier(atoi(remain));
-  if (ch == NULL || ch->ch_icon == NULL) {
-    pthread_mutex_unlock(&global_lock);
-    return 404;
-  };
-
-  snprintf(homepath, sizeof(homepath), "%s/icons", homedir);
-  inpath = NULL;
-  inpath2 = NULL;
-  outpath = NULL;
-  /* split icon to last component */
-  inpath = strdup(ch->ch_icon);
-  inpath2 = strtok(inpath, "/");
-  while (inpath2 != NULL) {
-    inpath2 = strtok(NULL, "/");
-    if (inpath2 != NULL) {
-      outpath = strdup(inpath2);
-    };
-  };
-  snprintf(iconpath, sizeof(iconpath), "%s/%s", homepath, outpath);
-  fp = fb_open(iconpath, 1, 0);
-  if (!fp) {
-    tvhlog(LOG_DEBUG, "page_logo", 
-           "failed to open %s redirecting to http link for icon (%s)", 
-           iconpath, ch->ch_icon);
-    http_redirect(hc, ch->ch_icon);
-    iconserve_queue_add ( ch->ch_id, ch->ch_icon );
-  } else {
-    tvhlog(LOG_DEBUG, "page_logo", "File %s opened", iconpath);
-    size = fb_size(fp);
-    mimetest_outbuf = strdup("image/jpeg");
-    http_send_header(hc, 200, mimetest_outbuf, size, NULL, NULL, 300, 0, NULL);
-    while (!fb_eof(fp)) {
-      ssize_t c = fb_read(fp, buf, sizeof(buf));
-      if (c < 0) {
-        break;
-      };
-      if (write(hc->hc_fd, buf, c) != c) {
-        break;
-      };
-    };
-    fb_close(fp);
-  };
-
-  pthread_mutex_unlock(&global_lock);
-  return 0;
-}
-
-/*
-*  Logo loader functions, called from http htsp
-*   Will return local cache url instead of icon stored
-*/
-const char
-*logo_query(int ch_id, const char *ch_icon)
-{
-  const char *setting = config_get_iconserve();
-  const char *serverip = config_get_serverip();
-  char outiconpath[255];
-  char *return_icon = strdup(ch_icon);
-
-  if (!setting || !*setting || (strcmp(setting, "off") == 0)) {
-    return return_icon;
-  };
-
-  if (!serverip || !*serverip) {
-    return return_icon;
-  };
-
-  snprintf(outiconpath, sizeof(outiconpath), 
-    "http://%s:%d/channellogo/%d", serverip, webui_port, ch_id);
-  return_icon = strdup(outiconpath);
-return return_icon;
-};
-
-/*
- * Icon grabber queue thread
- */
-void *iconserve_thread ( void *aux )
-{
-  iconserve_grab_queue_t *qe;
-  pthread_mutex_lock(&iconserve_mutex);
-  char *inpath, *inpath2;
-  const char *header_parse = NULL, *header_maxage = NULL;
-  const char *outpath = "none";
-  CURL *curl;
-  FILE *curl_fp, *curl_fp_header;
-  CURLcode res;
-  fb_file *fp;
-  char iconpath[100], iconpath_header[100];
-  char homepath[254];
-  const char *homedir = hts_settings_get_root();
-  struct stat fileStat;
-  int trigger_download = 0;
-  char buf[256];
-  int file = 0;
-  time_t seconds;
-  int dif, compare_seconds, rc;
-  const char *periodicdownload = config_get_iconserve_periodicdownload();
-  struct timespec timertrigger;
-  channel_t *ch;
-
-  tvhlog(LOG_INFO, "iconserve_thread", "Thread startup");
-  curl = curl_easy_init();
-  snprintf(homepath, sizeof(homepath), "%s/icons", homedir);
-  if(stat(homepath, &fileStat) == 0 || mkdir(homepath, 0700) == 0) {
-  if (curl) {
-  while (1) {
-
-    /* Get entry from queue */
-    qe = TAILQ_FIRST(&iconserve_queue);
-    /* Check for queue data */
-    if (!qe) { /* Queue Empty */
-      periodicdownload = config_get_iconserve_periodicdownload();
-      if (!periodicdownload || !*periodicdownload || 
-         (strcmp(periodicdownload, "off") == 0)) {
-        tvhlog(LOG_DEBUG, "iconserve_thread", "Non-timer wakeup");
-        rc = pthread_cond_wait(&iconserve_cond, &iconserve_mutex);
-      } else {
-        tvhlog(LOG_DEBUG, "iconserve_thread", "Timer wakeup set");
-        timertrigger.tv_sec  = time(NULL) + 86400;
-        timertrigger.tv_nsec = 0;
-        rc = pthread_cond_timedwait(&iconserve_cond, 
-                             &iconserve_mutex, &timertrigger);
-      };
-      if (rc == ETIMEDOUT) {
-        tvhlog(LOG_INFO, "iconserve_thread", "Thread wakeup by timer");
-        RB_FOREACH(ch, &channel_name_tree, ch_name_link) {
-          if (ch->ch_icon != NULL) {
-            iconserve_grab_queue_t *qe = calloc(1, sizeof(iconserve_grab_queue_t));
-            qe->chan_number = ch->ch_id;
-            qe->icon_url = ch->ch_icon;
-            TAILQ_INSERT_TAIL(&iconserve_queue, qe, iconserve_link);
-          };
-        };
-      };
-      continue;
-    }
-    TAILQ_REMOVE(&iconserve_queue, qe, iconserve_link);
-    pthread_mutex_unlock(&iconserve_mutex);
-
-    inpath = NULL;
-    inpath2 = NULL;
-    outpath = NULL;
-    curl_fp = NULL;
-    /* split icon to last component */
-    inpath = strdup(qe->icon_url);
-    inpath2 = strtok(inpath, "/");
-    while (inpath2 != NULL) {
-      inpath2 = strtok(NULL, "/");
-      if (inpath2 != NULL)
-        outpath = strdup(inpath2);
-    };
-    if (outpath != NULL) {
-      snprintf(iconpath, sizeof(iconpath), "%s/%s", homepath, outpath);
-      snprintf(iconpath_header, sizeof(iconpath_header), "%s/%s.head", 
-               homepath, outpath);
-      fp = fb_open(iconpath, 0, 1);
-      if (!fp) {
-        /* No file exists so grab immediately */
-        tvhlog(LOG_INFO, "logo_loader", "No logo, downloading file %s", outpath);
-        trigger_download = 1;
-      } else {
-        /* File exists so compare expiry times to re-grab */
-        fb_close(fp);
-        fp = fb_open(iconpath_header, 0, 0);
-        while (!fb_eof(fp)) {
-          memset(buf, 0, sizeof(buf));
-          if (!fb_gets(fp, buf, sizeof(buf) - 1)) break;
-          if (buf[strlen(buf) - 1] == '\n') {
-            buf[strlen(buf) - 1] = '\0';
-          };
-          if(strstr(buf, "Cache-Control: ")) {
-            header_parse = strtok(buf, "=");
-            header_parse = strtok ( NULL, "=");
-            header_maxage = strdup(header_parse);
-          };
-        };
-        fb_close(fp);
-        file=open(iconpath, O_RDONLY);
-        fstat(file,&fileStat);
-        seconds = time (NULL);
-        dif = difftime (seconds,fileStat.st_mtime);
-        compare_seconds=atoi(header_maxage);
-        if (dif > compare_seconds) {
-          tvhlog(LOG_DEBUG, "logo_loader", "Logo expired, downloading %s", outpath);
-          trigger_download = 1;
-        } else {
-          tvhlog(LOG_INFO, "logo_loader", "Logo not expired %s", outpath);
-        };
-        close(file);
-      };
-      if (trigger_download == 1) {
-        curl_fp=fopen(iconpath,"wb");
-        curl_fp_header=fopen(iconpath_header,"w");
-        curl_easy_setopt(curl, CURLOPT_URL, qe->icon_url);
-        curl_easy_setopt(curl, CURLOPT_WRITEDATA, curl_fp);
-        curl_easy_setopt(curl, CURLOPT_WRITEHEADER, curl_fp_header);
-        curl_easy_setopt(curl, CURLOPT_USERAGENT, "TVHeadend");
-        curl_easy_setopt(curl, CURLOPT_TIMEOUT, 120);
-        curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
-        res = curl_easy_perform(curl);
-        if (res == 0) {
-          tvhlog(LOG_INFO, "logo_loader", "Downloaded icon via curl (%s)", 
-                 qe->icon_url);
-        } else {
-          tvhlog(LOG_WARNING, "logo_loader", "Error with curl download (%s)",
-                 qe->icon_url);
-        };
-        fclose(curl_fp);
-        fclose(curl_fp_header);
-        trigger_download = 0;
-      };
-    };
-  }; /* while loop */
-  curl_easy_cleanup(curl);
-  } else {
-    tvhlog(LOG_WARNING, "iconserve", "CURL cannot initialise");
-  };
-  };
-  return NULL;
-};
-
-/*
- * Add data to the queue
- */
-void iconserve_queue_add ( int chan_number, char *icon_url )
-{
-  /* Create entry */
-  tvhlog(LOG_DEBUG, "iconserve_queue_add", "Adding chan_number to queue: %i",
-         chan_number);
-  iconserve_grab_queue_t *qe = calloc(1, sizeof(iconserve_grab_queue_t));
-  qe->chan_number = chan_number;
-  qe->icon_url = strdup(icon_url);
-
-  pthread_mutex_lock(&iconserve_mutex);
-  TAILQ_INSERT_TAIL(&iconserve_queue, qe, iconserve_link);
-  pthread_cond_signal(&iconserve_cond);
-  pthread_mutex_unlock(&iconserve_mutex);
-}
-
-
-/**
- * Loader for icons, check config params and pull them in one go
- */
-void
-logo_loader(void)
-{
-  channel_t *ch;
-  const char *setting = config_get_iconserve();
-  const char *serverip = config_get_serverip();
-
-  if (!setting || !*setting || (strcmp(setting, "off") == 0)) {
-    tvhlog(LOG_DEBUG, "logo_loader", "Disabled by config, skipping");
-    return;
-  };
-
-  if (!serverip || !*serverip) {
-    tvhlog(LOG_ALERT, "logo_loader", "No server IP, skipping icon cache");
-    return;
-  };
-
-
-  pthread_t tid;
-  pthread_mutex_init(&iconserve_mutex, NULL);
-  pthread_cond_init(&iconserve_cond, NULL);
-  TAILQ_INIT(&iconserve_queue);
-  /* Start thread - presumably permanently active */
-  pthread_create(&tid, NULL, iconserve_thread, NULL); // last param is passed as aux
-                                              // as this is single global 
-                                              // you can probably use global
-                                              // vars
-
-  tvhlog(LOG_INFO, "logo_loader", "Caching logos locally");
-  /* loop through channels and load logo files */
-  RB_FOREACH(ch, &channel_name_tree, ch_name_link) {
-    if (ch->ch_icon != NULL) {
-      iconserve_queue_add ( ch->ch_id, ch->ch_icon );
-    };
-  };
-  pthread_mutex_lock(&iconserve_mutex);
-  pthread_cond_signal(&iconserve_cond); // tell thread data is available
-  pthread_mutex_unlock(&iconserve_mutex);
-};
diff --git a/src/iconserve.h b/src/iconserve.h
deleted file mode 100644 (file)
index ff8a0f9..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- *  Icon file serve operations
- *  Copyright (C) 2012 Andy Brown
- *
- *  This program is free software: you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation, either version 3 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef ICONSERVE_H
-#define ICONSERVE_H
-
-#include "http.h"
-
-/* Struct of entries for icon grabbing
- * FIELD: chan_number
- * FIELD: icon url
- */
-typedef struct iconserve_grab_queue
-{
-  TAILQ_ENTRY(iconserve_grab_queue) iconserve_link;
-  int chan_number;
-  char *icon_url;
-} iconserve_grab_queue_t;
-
-
-int page_logo(http_connection_t *hc, const char *remain, void *opaque);
-size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream);
-
-void *iconserve_thread ( void *aux );
-
-const char *logo_query(int ch_id, const char *ch_icon);
-
-void iconserve_queue_add ( int chan_number, char *icon_url );
-
-void logo_loader(void);
-
-#endif /* ICONSERVE_H */
diff --git a/src/imagecache.c b/src/imagecache.c
new file mode 100644 (file)
index 0000000..224c72c
--- /dev/null
@@ -0,0 +1,440 @@
+/*
+ *  Icon file server operations
+ *  Copyright (C) 2012 Andy Brown
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <time.h>
+#include <assert.h>
+
+#include "settings.h"
+#include "tvheadend.h"
+#include "filebundle.h"
+#include "imagecache.h"
+#include "queue.h"
+#include "redblack.h"
+
+#if ENABLE_IMAGECACHE
+#define CURL_STATICLIB
+#include <curl/curl.h>
+#include <curl/easy.h>
+#endif
+
+// TODO: icon cache flushing?
+// TODO: md5 validation?
+// TODO: allow cache to be disabled by users
+
+/*
+ * Image metadata
+ */
+typedef struct imagecache_image
+{
+  int         id;       ///< Internal ID
+  const char *url;      ///< Upstream URL
+  int         failed;   ///< Last update failed
+  time_t      updated;  ///< Last time the file was checked
+  enum {
+    IDLE,
+    QUEUED,
+    FETCHING
+  }           state;    ///< fetch status
+
+  TAILQ_ENTRY(imagecache_image) q_link;   ///< Fetch Q link
+  RB_ENTRY(imagecache_image)    id_link;  ///< Index by ID
+  RB_ENTRY(imagecache_image)    url_link; ///< Index by URL
+} imagecache_image_t;
+
+static int                        _imagecache_id;
+static RB_HEAD(,imagecache_image) _imagecache_by_id;
+static RB_HEAD(,imagecache_image) _imagecache_by_url;
+
+pthread_mutex_t                   imagecache_mutex;
+
+static void  _imagecache_save   ( imagecache_image_t *img );
+
+#if ENABLE_IMAGECACHE
+uint32_t                              imagecache_enabled;
+uint32_t                              imagecache_ok_period;
+uint32_t                              imagecache_fail_period;
+
+static pthread_cond_t                 _imagecache_cond;
+static TAILQ_HEAD(, imagecache_image) _imagecache_queue;
+static void  _imagecache_add    ( imagecache_image_t *img );
+static void* _imagecache_thread ( void *p );
+static int   _imagecache_fetch  ( imagecache_image_t *img );
+#endif
+
+static int _url_cmp ( void *a, void *b )
+{
+  return strcmp(((imagecache_image_t*)a)->url, ((imagecache_image_t*)b)->url);
+}
+
+static int _id_cmp  ( void *a, void *b )
+{
+  return ((imagecache_image_t*)a)->id - ((imagecache_image_t*)b)->id;
+}
+
+/*
+ * Initialise
+ */
+void imagecache_init ( void )
+{
+  htsmsg_t *m, *e;
+  htsmsg_field_t *f;
+  imagecache_image_t *img, *i;
+  const char *url;
+  uint32_t id;
+
+  /* Init vars */
+  _imagecache_id         = 0;
+#if ENABLE_IMAGECACHE
+  imagecache_enabled     = 0;
+  imagecache_ok_period   = 24 * 7; // weekly
+  imagecache_fail_period = 24;     // daily
+#endif
+
+  /* Create threads */
+  pthread_mutex_init(&imagecache_mutex, NULL);
+#if ENABLE_IMAGECACHE
+  pthread_cond_init(&_imagecache_cond, NULL);
+  TAILQ_INIT(&_imagecache_queue);
+#endif
+
+  /* Load settings */
+#if ENABLE_IMAGECACHE
+  if ((m = hts_settings_load("imagecache/config"))) {
+    htsmsg_get_u32(m, "enabled", &imagecache_enabled);
+    htsmsg_get_u32(m, "ok_period", &imagecache_ok_period);
+    htsmsg_get_u32(m, "fail_period", &imagecache_fail_period);
+    htsmsg_destroy(m);
+  }
+#endif
+  if ((m = hts_settings_load("imagecache/meta"))) {
+    HTSMSG_FOREACH(f, m) {
+      if (!(e   = htsmsg_get_map_by_field(f))) continue;
+      if (!(id  = atoi(f->hmf_name))) continue;
+      if (!(url = htsmsg_get_str(e, "url"))) continue;
+      img          = calloc(1, sizeof(imagecache_image_t));
+      img->id      = id;
+      img->url     = strdup(url);
+      img->updated = htsmsg_get_s64_or_default(e, "updated", 0);
+      i = RB_INSERT_SORTED(&_imagecache_by_url, img, url_link, _url_cmp);
+      if (i) {
+        hts_settings_remove("imagecache/meta/%d", id);
+        hts_settings_remove("imagecache/data/%d", id);
+        free(img);
+        continue;
+      }
+      i = RB_INSERT_SORTED(&_imagecache_by_id, img, id_link, _id_cmp);
+      assert(!i);
+      if (id > _imagecache_id)
+        _imagecache_id = id;
+#if ENABLE_IMAGECACHE
+      if (!img->updated)
+        _imagecache_add(img);
+#endif
+    }
+    htsmsg_destroy(m);
+  }
+
+  /* Start threads */
+#if ENABLE_IMAGECACHE
+  {
+    pthread_t tid;
+    pthread_create(&tid, NULL, _imagecache_thread, NULL);
+  }
+#endif
+}
+
+/*
+ * Save settings
+ */
+#if ENABLE_IMAGECACHE
+void imagecache_save ( void )
+{
+  htsmsg_t *m = htsmsg_create_map();
+  htsmsg_add_u32(m, "enabled",     imagecache_enabled);
+  htsmsg_add_u32(m, "ok_period",   imagecache_ok_period);
+  htsmsg_add_u32(m, "fail_period", imagecache_fail_period);
+  hts_settings_save(m, "imagecache/config");
+}
+
+/*
+ * Enable/disable
+ */
+int imagecache_set_enabled ( uint32_t e )
+{
+  if (e == imagecache_enabled)
+    return 0;
+  imagecache_enabled = e;
+  if (e)
+    pthread_cond_broadcast(&_imagecache_cond);
+  return 1;
+}
+
+/*
+ * Set ok period
+ */
+int imagecache_set_ok_period ( uint32_t p )
+{
+  if (p == imagecache_ok_period)
+    return 0;
+  imagecache_ok_period = p;
+  return 1;
+}
+
+/*
+ * Set fail period
+ */
+int imagecache_set_fail_period ( uint32_t p )
+{
+  if (p == imagecache_fail_period)
+    return 0;
+  imagecache_fail_period = p;
+  return 1;
+}
+#endif
+
+/*
+ * Fetch a URLs ID
+ */
+uint32_t imagecache_get_id ( const char *url )
+{
+  uint32_t id = 0;
+  imagecache_image_t *i;
+  static imagecache_image_t *skel = NULL;
+
+  /* Invalid */
+  if (!url)
+    return 0;
+
+  /* Disabled */
+#if !ENABLE_IMAGECACHE
+  if (strncasecmp(url, "file://", 7))
+    return 0;
+#endif
+
+  /* Skeleton */
+  if (!skel)
+    skel = calloc(1, sizeof(imagecache_image_t));
+  skel->url = url;
+
+  /* Create/Find */
+  pthread_mutex_lock(&imagecache_mutex);
+  i = RB_INSERT_SORTED(&_imagecache_by_url, skel, url_link, _url_cmp);
+  if (!i) {
+    i      = skel;
+    i->url = strdup(url);
+    i->id  = ++_imagecache_id;
+    skel   = RB_INSERT_SORTED(&_imagecache_by_id, i, id_link, _id_cmp);
+    assert(!skel);
+#if ENABLE_IMAGECACHE
+    _imagecache_add(i);
+#endif
+    _imagecache_save(i);
+  }
+#if ENABLE_IMAGECACHE
+  if (!strncasecmp(url, "file://", 7) || imagecache_enabled)
+    id = i->id;
+#else
+  if (!strncasecmp(url, "file://", 7))
+    id = i->id;
+#endif
+  pthread_mutex_unlock(&imagecache_mutex);
+  
+  return id;
+}
+
+/*
+ * Get data
+ */
+int imagecache_open ( uint32_t id )
+{
+  imagecache_image_t skel, *i;
+  int fd = -1;
+
+  pthread_mutex_lock(&imagecache_mutex);
+
+  /* Find */
+  skel.id = id;
+  i = RB_FIND(&_imagecache_by_id, &skel, id_link, _id_cmp);
+
+  /* Invalid */
+  if (!i) {
+    pthread_mutex_unlock(&imagecache_mutex);
+    return -1;
+  }
+
+  /* Local file */
+  if (!strncasecmp(i->url, "file://", 7))
+    fd = open(i->url + 7, O_RDONLY);
+
+  /* Remote file */
+#if ENABLE_IMAGECACHE
+  else if (imagecache_enabled) {
+    struct timespec ts;
+    int err;
+    if (i->updated) {
+      // use existing
+    } else if (i->state == FETCHING) {
+      ts.tv_nsec = 0;
+      time(&ts.tv_sec);
+      ts.tv_sec += 10; // TODO: sensible timeout?
+      err = pthread_cond_timedwait(&_imagecache_cond, &imagecache_mutex, &ts);
+      if (err == ETIMEDOUT) {
+        pthread_mutex_unlock(&imagecache_mutex);
+        return -1;
+      }
+    } else if (i->state == QUEUED) {
+      i->state = FETCHING;
+      TAILQ_REMOVE(&_imagecache_queue, i, q_link);
+      pthread_mutex_unlock(&imagecache_mutex);
+      if (_imagecache_fetch(i))
+        return -1;
+      pthread_mutex_lock(&imagecache_mutex);
+    }
+    fd = hts_settings_open_file(0, "imagecache/data/%d", i->id);
+  }
+#endif
+  pthread_mutex_unlock(&imagecache_mutex);
+
+  return fd;
+}
+
+static void _imagecache_save ( imagecache_image_t *img )
+{
+  htsmsg_t *m = htsmsg_create_map();
+  
+  htsmsg_add_str(m, "url", img->url);
+  if (img->updated)
+    htsmsg_add_s64(m, "updated", img->updated);
+
+  hts_settings_save(m, "imagecache/meta/%d", img->id);
+}
+
+#if ENABLE_IMAGECACHE
+static void _imagecache_add ( imagecache_image_t *img )
+{
+  if (strncasecmp("file://", img->url, 7)) {
+    img->state = QUEUED;
+    TAILQ_INSERT_TAIL(&_imagecache_queue, img, q_link);
+    pthread_cond_broadcast(&_imagecache_cond);
+  } else {
+    time(&img->updated);
+  }
+}
+
+static void *_imagecache_thread ( void *p )
+{
+  int err;
+  imagecache_image_t *img;
+  struct timespec ts;
+  ts.tv_nsec = 0;
+
+  while (1) {
+
+    /* Get entry */
+    pthread_mutex_lock(&imagecache_mutex);
+    if (!imagecache_enabled) {
+      pthread_cond_wait(&_imagecache_cond, &imagecache_mutex);
+      pthread_mutex_unlock(&imagecache_mutex);
+      continue;
+    }
+    img = TAILQ_FIRST(&_imagecache_queue);
+    if (!img) {
+      time(&ts.tv_sec);
+      ts.tv_sec += 60;
+      err = pthread_cond_timedwait(&_imagecache_cond, &imagecache_mutex, &ts);
+      if (err == ETIMEDOUT) {
+        RB_FOREACH(img, &_imagecache_by_url, url_link) {
+          if (img->state != IDLE) continue;
+          if ((ts.tv_sec - img->updated) >
+              (img->failed ? imagecache_fail_period : imagecache_ok_period))
+            _imagecache_add(img);
+        }
+      }
+      pthread_mutex_unlock(&imagecache_mutex);
+      continue;
+    }
+    img->state = FETCHING;
+    TAILQ_REMOVE(&_imagecache_queue, img, q_link);
+    pthread_mutex_unlock(&imagecache_mutex);
+
+    /* Fetch */
+    _imagecache_fetch(img);
+  }
+
+  return NULL;
+}
+
+static int _imagecache_fetch ( imagecache_image_t *img )
+{
+  int res;
+  CURL *curl;
+  FILE *fp;
+  char tmp[256], path[256];
+
+  /* Open file  */
+  if (hts_settings_buildpath(path, sizeof(path), "imagecache/data/%d",
+                              img->id))
+    return 1;
+  if (hts_settings_makedirs(path))
+    return 1;
+  snprintf(tmp, sizeof(tmp), "%s.tmp", path);
+  if (!(fp = fopen(tmp, "wb")))
+    return 1;
+  
+  /* Fetch file */
+  tvhlog(LOG_DEBUG, "imagecache", "fetch %s", img->url);
+  curl = curl_easy_init();
+  curl_easy_setopt(curl, CURLOPT_URL,         img->url);
+  curl_easy_setopt(curl, CURLOPT_WRITEDATA,   fp);
+  curl_easy_setopt(curl, CURLOPT_USERAGENT,   "TVHeadend");
+  curl_easy_setopt(curl, CURLOPT_TIMEOUT,     120);
+  curl_easy_setopt(curl, CURLOPT_NOPROGRESS,  1);
+  curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
+  res = curl_easy_perform(curl);
+  curl_easy_cleanup(curl);
+  fclose(fp);
+
+  /* Process */
+  pthread_mutex_lock(&imagecache_mutex);
+  img->state = IDLE;
+  time(&img->updated); // even if failed (possibly request sooner?)
+  if (res) {
+    img->failed = 1;
+    unlink(tmp);
+    tvhlog(LOG_WARNING, "imagecache", "failed to download %s", img->url);
+  } else {
+    img->failed = 0;
+    unlink(path);
+    rename(tmp, path);
+    tvhlog(LOG_DEBUG, "imagecache", "downloaded %s", img->url);
+  }
+  _imagecache_save(img);
+  pthread_cond_broadcast(&_imagecache_cond);
+  pthread_mutex_unlock(&imagecache_mutex);
+  
+  return res;
+};
+#endif
diff --git a/src/imagecache.h b/src/imagecache.h
new file mode 100644 (file)
index 0000000..5776f46
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ *  Icon file serve operations
+ *  Copyright (C) 2012 Andy Brown
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __IMAGE_CACHE_H__
+#define __IMAGE_CACHE_H__
+
+#include <pthread.h>
+
+extern uint32_t imagecache_enabled;
+extern uint32_t imagecache_ok_period;
+extern uint32_t imagecache_fail_period;
+
+extern pthread_mutex_t imagecache_mutex;
+
+void     imagecache_init     ( void );
+
+void     imagecache_save     ( void );
+
+int      imagecache_set_enabled     ( uint32_t e )
+  __attribute__((warn_unused_result));
+int      imagecache_set_ok_period   ( uint32_t e )
+  __attribute__((warn_unused_result));
+int      imagecache_set_fail_period ( uint32_t e )
+  __attribute__((warn_unused_result));
+
+// Note: will return 0 if invalid (must serve original URL)
+uint32_t imagecache_get_id  ( const char *url );
+
+int      imagecache_open    ( uint32_t id );
+
+#define htsmsg_add_imageurl(_msg, _fld, _fmt, _url)\
+  {\
+    char _tmp[64];\
+    uint32_t _id = imagecache_get_id(_url);\
+    if (_id) {\
+      snprintf(_tmp, sizeof(_tmp), _fmt, _id);\
+    } else {\
+      htsmsg_add_str(_msg, _fld, _url);\
+    }\
+  }
+
+#endif /* __IMAGE_CACHE_H__ */
index 1bb3b50941cd3e47985a4c5be47b1e30e00b2985..d56c63cb8448f93b3f76f152c933477b9d2ac3e7 100644 (file)
@@ -60,7 +60,7 @@
 #include "ffdecsa/FFdecsa.h"
 #include "muxes.h"
 #include "config2.h"
-#include "iconserve.h"
+#include "imagecache.h"
 
 int running;
 time_t dispatch_clock;
@@ -89,6 +89,9 @@ const char *tvheadend_capabilities[] = {
 #endif
 #if ENABLE_LINUXDVB
   "linuxdvb",
+#endif
+#if ENABLE_IMAGECACHE
+  "imagecache",
 #endif
   NULL
 };
@@ -466,6 +469,8 @@ main(int argc, char **argv)
 
   config_init();
 
+  imagecache_init();
+
   service_init();
 
   channels_init();
@@ -489,8 +494,6 @@ main(int argc, char **argv)
   http_server_init();
   webui_init();
 
-  logo_loader();
-
   serviceprobe_init();
 
 #if ENABLE_CWC
index c98fc2fdee31cfe2585675b261f0cf8febd7440f..da46c455dc38c60b8cc7109433a989eeb7631a18 100644 (file)
@@ -101,7 +101,7 @@ hts_settings_makedirs ( const char *inpath )
  *
  */
 static void
-hts_settings_buildpath
+_hts_settings_buildpath
   (char *dst, size_t dstsize, const char *fmt, va_list ap, const char *prefix)
 {
   char tmp[256];
@@ -120,6 +120,18 @@ hts_settings_buildpath
   }
 }
 
+int
+hts_settings_buildpath
+  (char *dst, size_t dstsize, const char *fmt, ...)
+{
+  va_list va;
+  va_start(va, fmt);
+  if (!settingspath)
+    return 1;
+  _hts_settings_buildpath(dst, dstsize, fmt, va, settingspath);
+  return 0;
+}
+
 /**
  *
  */
@@ -139,7 +151,7 @@ hts_settings_save(htsmsg_t *record, const char *pathfmt, ...)
 
   /* Clean the path */
   va_start(ap, pathfmt);
-  hts_settings_buildpath(path, sizeof(path), pathfmt, ap, settingspath);
+  _hts_settings_buildpath(path, sizeof(path), pathfmt, ap, settingspath);
   va_end(ap);
 
   /* Create directories */
@@ -261,16 +273,16 @@ hts_settings_load(const char *pathfmt, ...)
 
   /* Try normal path */
   va_start(ap, pathfmt);
-  hts_settings_buildpath(fullpath, sizeof(fullpath), 
-                         pathfmt, ap, settingspath);
+  _hts_settings_buildpath(fullpath, sizeof(fullpath), 
+                          pathfmt, ap, settingspath);
   va_end(ap);
   ret = _hts_settings_load(fullpath);
 
   /* Try bundle path */
   if (!ret && *pathfmt != '/') {
     va_start(ap, pathfmt);
-    hts_settings_buildpath(fullpath, sizeof(fullpath),
-                           pathfmt, ap, "data/conf");
+    _hts_settings_buildpath(fullpath, sizeof(fullpath),
+                            pathfmt, ap, "data/conf");
     va_end(ap);
     ret = _hts_settings_load(fullpath);
   }
@@ -289,7 +301,7 @@ hts_settings_remove(const char *pathfmt, ...)
   struct stat st;
 
   va_start(ap, pathfmt);
-   hts_settings_buildpath(fullpath, sizeof(fullpath),
+  _hts_settings_buildpath(fullpath, sizeof(fullpath),
                           pathfmt, ap, settingspath);
   va_end(ap);
   if (stat(fullpath, &st) == 0) {
@@ -311,7 +323,7 @@ hts_settings_open_file(int for_write, const char *pathfmt, ...)
 
   /* Build path */
   va_start(ap, pathfmt);
-  hts_settings_buildpath(path, sizeof(path), pathfmt, ap, settingspath);
+  _hts_settings_buildpath(path, sizeof(path), pathfmt, ap, settingspath);
   va_end(ap);
 
   /* Create directories */
index 7f0bb8d025811072d6e2cda8a1d98ed18bce5f78..a1db839c589d868e370775c15c69c778af2ccf63 100644 (file)
@@ -34,6 +34,8 @@ const char *hts_settings_get_root(void);
 
 int hts_settings_open_file(int for_write, const char *pathfmt, ...);
 
+int hts_settings_buildpath(char *dst, size_t dstsize, const char *pathfmt, ...);
+
 int hts_settings_makedirs ( const char *path );
 
 #endif /* HTSSETTINGS_H__ */ 
index 6999eacf1e555ae0a029249304a519693d255179..1fc3a8bfd050b51cb79d723b662300ef75bcf765 100644 (file)
@@ -47,7 +47,7 @@
 #include "config2.h"
 #include "lang_codes.h"
 #include "subscriptions.h"
-#include "iconserve.h"
+#include "imagecache.h"
 
 /**
  *
@@ -859,7 +859,7 @@ extjs_epg(http_connection_t *hc, const char *remain, void *opaque)
     htsmsg_add_str(m, "channel", ch->ch_name);
     htsmsg_add_u32(m, "channelid", ch->ch_id);
     if(ch->ch_icon != NULL)
-            htsmsg_add_str(m, "chicon", logo_query(ch->ch_id, ch->ch_icon));
+      htsmsg_add_imageurl(m, "chicon", "imagecache/%d", ch->ch_icon);
 
     if((s = epg_episode_get_title(ee, lang)))
       htsmsg_add_str(m, "title", s);
@@ -941,7 +941,8 @@ extjs_epgrelated(http_connection_t *hc, const char *remain, void *opaque)
           m = htsmsg_create_map();
           htsmsg_add_u32(m, "id", ebc->id);
           if ( ch->ch_name ) htsmsg_add_str(m, "channel", ch->ch_name);
-          if ( ch->ch_icon ) htsmsg_add_str(m, "chicon", logo_query(ch->ch_id, ch->ch_icon));
+          if (ch->ch_icon)
+            htsmsg_add_imageurl(m, "chicon", "imagecache/%d", ch->ch_icon);
           htsmsg_add_u32(m, "start", ebc->start);
           htsmsg_add_msg(array, NULL, m);
         }
@@ -1340,8 +1341,9 @@ extjs_dvrlist(http_connection_t *hc, const char *remain, void *opaque,
 
     if(de->de_channel != NULL) {
       htsmsg_add_str(m, "channel", de->de_channel->ch_name);
-      if(de->de_channel->ch_icon != NULL)
-       htsmsg_add_str(m, "chicon", logo_query(de->de_channel->ch_id, de->de_channel->ch_icon));
+      if (de->de_channel->ch_icon)
+        htsmsg_add_imageurl(m, "chicon", "imagecache/%d",
+                            de->de_channel->ch_icon);
     }
 
     htsmsg_add_str(m, "config_name", de->de_config_name);
@@ -1915,40 +1917,54 @@ extjs_config(http_connection_t *hc, const char *remain, void *opaque)
 
   pthread_mutex_unlock(&global_lock);
 
-  /* Basic settings (not the advanced schedule) */
+  /* Basic settings */
   if(!strcmp(op, "loadSettings")) {
+
+    /* Misc */
     pthread_mutex_lock(&global_lock);
     m = config_get_all();
     pthread_mutex_unlock(&global_lock);
+
+    /* Image cache */
+#if ENABLE_IMAGECACHE
+    pthread_mutex_lock(&imagecache_mutex);
+    htsmsg_add_u32(m, "imagecache_enabled",     imagecache_enabled);
+    htsmsg_add_u32(m, "imagecache_ok_period",   imagecache_ok_period);
+    htsmsg_add_u32(m, "imagecache_fail_period", imagecache_fail_period);
+    pthread_mutex_unlock(&imagecache_mutex);
+#endif
+
     if (!m) return HTTP_STATUS_BAD_REQUEST;
     out = json_single_record(m, "config");
 
   /* Save settings */
   } else if (!strcmp(op, "saveSettings") ) {
     int save = 0;
+
+    /* Misc settings */
     pthread_mutex_lock(&global_lock);
     if ((str = http_arg_get(&hc->hc_req_args, "muxconfpath")))
       save |= config_set_muxconfpath(str);
     if ((str = http_arg_get(&hc->hc_req_args, "language")))
       save |= config_set_language(str);
-    str = http_arg_get(&hc->hc_req_args, "iconserve");
-    if (str != NULL) {
-     save |= config_set_iconserve(str);
-    } else {
-     save |= config_set_iconserve("off");
-    };
-    str = http_arg_get(&hc->hc_req_args, "iconserve_periodicdownload");
-    if (str != NULL) {
-     save |= config_set_iconserve_periodicdownload(str);
-    } else {
-     save |= config_set_iconserve_periodicdownload("off");
-    };
-    if ((str = http_arg_get(&hc->hc_req_args, "serverip")))
-      save |= config_set_serverip(str);
-    if (save) config_save();
-    /* trigger the iconserve init routine */
-    logo_loader();
+    if (save)
+      config_save();
     pthread_mutex_unlock(&global_lock);
+  
+    /* Image Cache */
+#if ENABLE_IMAGECACHE
+    pthread_mutex_lock(&imagecache_mutex);
+    str = http_arg_get(&hc->hc_req_args, "imagecache_enabled");
+    save = imagecache_set_enabled(!!str);
+    if ((str = http_arg_get(&hc->hc_req_args, "imagecache_ok_period")))
+      save |= imagecache_set_ok_period(atoi(str));
+    if ((str = http_arg_get(&hc->hc_req_args, "imagecache_fail_period")))
+      save |= imagecache_set_fail_period(atoi(str));
+    if (save)
+      imagecache_save();
+    pthread_mutex_unlock(&imagecache_mutex);
+#endif
+
     out = htsmsg_create_map();
     htsmsg_add_u32(out, "success", 1);
 
index 294251432168d80ff4234b656192c6ddeedae05f..603fd15843fba6659e46df047aa6cb19334102ba 100644 (file)
@@ -30,7 +30,6 @@
 #include "epg.h"
 #include "psi.h"
 #include "channels.h"
-#include "iconserve.h"
 #if ENABLE_LINUXDVB
 #include "dvr/dvr.h"
 #include "dvb/dvb.h"
@@ -73,7 +72,7 @@ dumpchannels(htsbuf_queue_t *hq)
                   ch->ch_refcount,
                   ch->ch_zombie,
                   ch->ch_number,
-                  logo_query(ch->ch_id, ch->ch_icon) ?: "<none set>");
+                  ch->ch_icon ?: "<none set>");
   }
 }
 
index a862e0bbf5f14a3180a53e0b4e2cdff1b6087973..42eb6082b6b8df3c2a5e397710995990b6e8e12a 100644 (file)
@@ -37,12 +37,18 @@ tvheadend.miscconf = function() {
         */
        var confreader = new Ext.data.JsonReader({
                root : 'config'
-       }, [ 'muxconfpath', 'language', 'iconserve', 'serverip' ]);
+       }, [ 'muxconfpath', 'language',
+       'imagecache_enabled', 'imagecache_ok_period',
+       'imagecache_fail_period']);
 
        /* ****************************************************************
         * Form Fields
         * ***************************************************************/
 
+  /*
+   * DVB path
+   */
+
        var dvbscanPath = new Ext.form.TextField({
                fieldLabel : 'DVB scan files path',
                name : 'muxconfpath',
@@ -50,21 +56,9 @@ tvheadend.miscconf = function() {
                width: 400
        });
 
-        var iconServeConfig = new Ext.form.Checkbox({
-                name : 'iconserve',
-                fieldLabel : 'Cache channel icons'
-        });
-       var iconPeriodicDownload = new Ext.form.Checkbox({
-               name : 'iconserve_periodicdownload',
-               fieldLabel : 'Periodically check for updated icons'
-       });
-        var serveripConfig = new Ext.form.TextField({
-                fieldLabel : 'TVH Server IP address',
-                name : 'serverip',
-                allowBlank : true,
-                width: 150
-        });
-
+  /*
+   * Language
+   */
 
        var language = new Ext.ux.ItemSelector({
                name: 'language',
@@ -81,6 +75,34 @@ tvheadend.miscconf = function() {
                fromLegend: 'Available'
        });
 
+  /*
+   * Image cache
+   */
+  var imagecacheEnabled = new Ext.form.Checkbox({
+    name: 'imagecache_enabled',
+    fieldLabel: 'Enabled',
+  });
+
+  var imagecacheOkPeriod = new Ext.form.NumberField({
+    name: 'imagecache_ok_period',
+    fieldLabel: 'Re-fetch period (hours)'
+  });
+
+  var imagecacheFailPeriod = new Ext.form.NumberField({
+    name: 'imagecache_fail_period',
+    fieldLabel: 'Re-try period (hours)',
+  });
+
+  var imagecachePanel = new Ext.form.FieldSet({
+    title: 'Image Caching',
+    width: 700,
+    autoHeight: true,
+    collapsible: true,
+    items : [ imagecacheEnabled, imagecacheOkPeriod, imagecacheFailPeriod ]
+  });
+  if (tvheadend.capabilities.indexOf('imagecache') == -1)
+    imagecachePanel.hide();
+
        /* ****************************************************************
         * Form
         * ***************************************************************/
@@ -111,7 +133,8 @@ tvheadend.miscconf = function() {
                layout : 'form',
                defaultType : 'textfield',
                autoHeight : true,
-               items : [ language, dvbscanPath, iconServeConfig, iconPeriodicDownload, serveripConfig ],
+               items : [ language, dvbscanPath,
+              imagecachePanel ],
                tbar : [ saveButton, '->', helpButton ]
        });
 
index 6376c812456f96e40d8e9684c97937dec1d1419d..69ccadf0e6326b9311fc6efd36ecfdcc5707a1a5 100644 (file)
@@ -44,7 +44,7 @@
 #include "muxer.h"
 #include "dvb/dvb.h"
 #include "dvb/dvb_support.h"
-#include "iconserve.h"
+#include "imagecache.h"
 
 /**
  *
@@ -868,7 +868,47 @@ page_dvrfile(http_connection_t *hc, const char *remain, void *opaque)
   return 0;
 }
 
+/**
+ * Fetch image cache image
+ */
+/**
+ * Static download of a file from the filesystem
+ */
+static int
+page_imagecache(http_connection_t *hc, const char *remain, void *opaque)
+{
+  uint32_t id;
+  int fd;
+  char buf[8192];
+  struct stat st;
+  ssize_t c;
+
+  if(remain == NULL)
+    return 404;
+
+  if(sscanf(remain, "%d", &id) != 1)
+    return HTTP_STATUS_BAD_REQUEST;
 
+  if ((fd = imagecache_open(id)) < 0)
+    return 404;
+  if (fstat(fd, &st)) {
+    close(fd);
+    return 404;
+  }
+
+  http_send_header(hc, 200, NULL, st.st_size, 0, NULL, 10, 0, NULL);
+
+  while (1) {
+    c = read(fd, buf, sizeof(buf));
+    if (c <= 0)
+      break;
+    if (tvh_write(hc->hc_fd, buf, c))
+      break;
+  }
+  close(fd);
+
+  return 0;
+}
 
 /**
  *
@@ -910,7 +950,7 @@ webui_init(void)
 
   http_path_add("/stream",  NULL, http_stream,  ACCESS_STREAMING);
 
-  http_path_add("/channellogo", NULL, page_logo, ACCESS_ANONYMOUS);
+  http_path_add("/imagecache", NULL, page_imagecache, ACCESS_ANONYMOUS);
 
   webui_static_content("/static",        "src/webui/static");
   webui_static_content("/docs",          "docs/html");