diff --git a/Makefile b/Makefile index 3d8fab24..c63cbe58 100644 --- 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 +LDFLAGS += -lrt -ldl -lpthread -lm -lcurl # # Other config @@ -140,6 +140,8 @@ SRCS += src/muxer.c \ src/muxer_pass.c \ src/muxer_tvh.c \ +SRCS += src/iconserve.c \ + # # Optional code # diff --git a/docs/html/config_misc.html b/docs/html/config_misc.html index 00e00b07..5f11cf7b 100644 --- a/docs/html/config_misc.html +++ b/docs/html/config_misc.html @@ -20,5 +20,19 @@ dvb-apps stores these in /usr/share/dvb/. Leave blank to use TVH's internal file set. +
Cache channel icons: +
+ Enable the caching of channel icons. This will cause TVH to download channel + icons locally, and then when requested via HTSP clients the URL for the icon + (or logo) will be retrieved from the TVH web server rather than fetched each + time by the HTSP client. + This REQUIRES the TVH server IP address field to also be populated + +
TVH Server IP Address: +
+ Enter the IP address of the TVH server used for HTSP clients. This permits the + above cache channel icons to work (TVH Clients are directed to the IP address + entered here to retrieve channel icons from) + diff --git a/src/config2.c b/src/config2.c index 5bcbd0d1..b90db4fe 100644 --- a/src/config2.c +++ b/src/config2.c @@ -74,3 +74,50 @@ 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; +}; diff --git a/src/config2.h b/src/config2.h index cd68e306..6e90be6f 100644 --- a/src/config2.h +++ b/src/config2.h @@ -32,6 +32,18 @@ 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)); diff --git a/src/htsp_server.c b/src/htsp_server.c index ebbb07a2..ba10139a 100644 --- a/src/htsp_server.c +++ b/src/htsp_server.c @@ -42,6 +42,8 @@ #include "htsmsg_binary.h" #include "epg.h" #include "plumbing/tsfix.h" +#include "iconserve.h" +#include "config2.h" #include #include "settings.h" @@ -447,8 +449,10 @@ 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", ch->ch_icon); + + if(ch->ch_icon != NULL) { + htsmsg_add_str(out, "channelIcon", logo_query(ch->ch_id, ch->ch_icon)); + }; now = ch->ch_epg_now; next = ch->ch_epg_next; diff --git a/src/http.c b/src/http.c index dee8e1f8..e87ec543 100644 --- a/src/http.c +++ b/src/http.c @@ -173,18 +173,18 @@ http_send_header(http_connection_t *hc, int rc, const char *content, tm = gmtime_r(&t, &tm0); htsbuf_qprintf(&hdrs, - "Last-Modified: %s, %02d %s %d %02d:%02d:%02d GMT\r\n", - cachedays[tm->tm_wday], tm->tm_year + 1900, - cachemonths[tm->tm_mon], tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); + "Last-Modified: %s, %d %s %02d %02d:%02d:%02d GMT\r\n", + cachedays[tm->tm_wday], tm->tm_mday, + cachemonths[tm->tm_mon], tm->tm_year + 1900, + tm->tm_hour, tm->tm_min, tm->tm_sec); t += maxage; tm = gmtime_r(&t, &tm0); htsbuf_qprintf(&hdrs, - "Expires: %s, %02d %s %d %02d:%02d:%02d GMT\r\n", - cachedays[tm->tm_wday], tm->tm_year + 1900, - cachemonths[tm->tm_mon], tm->tm_mday, + "Expires: %s, %d %s %02d %02d:%02d:%02d GMT\r\n", + cachedays[tm->tm_wday], tm->tm_mday, + cachemonths[tm->tm_mon], tm->tm_year + 1900, tm->tm_hour, tm->tm_min, tm->tm_sec); htsbuf_qprintf(&hdrs, "Cache-Control: max-age=%d\r\n", maxage); diff --git a/src/iconserve.c b/src/iconserve.c new file mode 100644 index 00000000..85f0fe04 --- /dev/null +++ b/src/iconserve.c @@ -0,0 +1,358 @@ +/* + * 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 . + */ + +#define CURL_STATICLIB +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 new file mode 100644 index 00000000..ff8a0f92 --- /dev/null +++ b/src/iconserve.h @@ -0,0 +1,47 @@ +/* + * 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 . + */ + +#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/main.c b/src/main.c index 73afb075..1bb3b509 100644 --- a/src/main.c +++ b/src/main.c @@ -60,6 +60,7 @@ #include "ffdecsa/FFdecsa.h" #include "muxes.h" #include "config2.h" +#include "iconserve.h" int running; time_t dispatch_clock; @@ -488,6 +489,8 @@ main(int argc, char **argv) http_server_init(); webui_init(); + logo_loader(); + serviceprobe_init(); #if ENABLE_CWC diff --git a/src/webui/extjs.c b/src/webui/extjs.c index bf254d03..6999eacf 100644 --- a/src/webui/extjs.c +++ b/src/webui/extjs.c @@ -47,6 +47,7 @@ #include "config2.h" #include "lang_codes.h" #include "subscriptions.h" +#include "iconserve.h" /** * @@ -858,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", ch->ch_icon); + htsmsg_add_str(m, "chicon", logo_query(ch->ch_id, ch->ch_icon)); if((s = epg_episode_get_title(ee, lang))) htsmsg_add_str(m, "title", s); @@ -940,7 +941,7 @@ 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", ch->ch_icon); + if ( ch->ch_icon ) htsmsg_add_str(m, "chicon", logo_query(ch->ch_id, ch->ch_icon)); htsmsg_add_u32(m, "start", ebc->start); htsmsg_add_msg(array, NULL, m); } @@ -1340,7 +1341,7 @@ 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", de->de_channel->ch_icon); + htsmsg_add_str(m, "chicon", logo_query(de->de_channel->ch_id, de->de_channel->ch_icon)); } htsmsg_add_str(m, "config_name", de->de_config_name); @@ -1930,7 +1931,23 @@ extjs_config(http_connection_t *hc, const char *remain, void *opaque) 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(); pthread_mutex_unlock(&global_lock); out = htsmsg_create_map(); htsmsg_add_u32(out, "success", 1); diff --git a/src/webui/simpleui.c b/src/webui/simpleui.c index 0950fd72..faabaf8d 100644 --- a/src/webui/simpleui.c +++ b/src/webui/simpleui.c @@ -482,7 +482,5 @@ simpleui_start(void) http_path_add("/simple.html", NULL, page_simple, ACCESS_SIMPLE); http_path_add("/eventinfo", NULL, page_einfo, ACCESS_SIMPLE); http_path_add("/pvrinfo", NULL, page_pvrinfo, ACCESS_SIMPLE); - http_path_add("/status.xml", NULL, page_status, ACCESS_SIMPLE); + http_path_add("/status.xml", NULL, page_status, ACCESS_SIMPLE); } - - diff --git a/src/webui/statedump.c b/src/webui/statedump.c index 603fd158..29425143 100644 --- a/src/webui/statedump.c +++ b/src/webui/statedump.c @@ -30,6 +30,7 @@ #include "epg.h" #include "psi.h" #include "channels.h" +#include "iconserve.h" #if ENABLE_LINUXDVB #include "dvr/dvr.h" #include "dvb/dvb.h" @@ -72,7 +73,7 @@ dumpchannels(htsbuf_queue_t *hq) ch->ch_refcount, ch->ch_zombie, ch->ch_number, - ch->ch_icon ?: ""); + logo_query(ch->ch_id, ch->ch_icon) ?: ""); } } diff --git a/src/webui/static/app/config.js b/src/webui/static/app/config.js index 2c9b6a86..a862e0bb 100644 --- a/src/webui/static/app/config.js +++ b/src/webui/static/app/config.js @@ -37,7 +37,7 @@ tvheadend.miscconf = function() { */ var confreader = new Ext.data.JsonReader({ root : 'config' - }, [ 'muxconfpath', 'language' ]); + }, [ 'muxconfpath', 'language', 'iconserve', 'serverip' ]); /* **************************************************************** * Form Fields @@ -50,6 +50,22 @@ 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 + }); + + var language = new Ext.ux.ItemSelector({ name: 'language', fromStore: tvheadend.languages, @@ -95,7 +111,7 @@ tvheadend.miscconf = function() { layout : 'form', defaultType : 'textfield', autoHeight : true, - items : [ language, dvbscanPath ], + items : [ language, dvbscanPath, iconServeConfig, iconPeriodicDownload, serveripConfig ], tbar : [ saveButton, '->', helpButton ] }); diff --git a/src/webui/webui.c b/src/webui/webui.c index 0f3560c5..6376c812 100644 --- a/src/webui/webui.c +++ b/src/webui/webui.c @@ -44,6 +44,7 @@ #include "muxer.h" #include "dvb/dvb.h" #include "dvb/dvb_support.h" +#include "iconserve.h" /** * @@ -95,7 +96,7 @@ page_root2(http_connection_t *hc, const char *remain, void *opaque) /** * Static download of a file from the filesystem */ -static int +int page_static_file(http_connection_t *hc, const char *remain, void *opaque) { int ret = 0; @@ -909,6 +910,8 @@ webui_init(void) http_path_add("/stream", NULL, http_stream, ACCESS_STREAMING); + http_path_add("/channellogo", NULL, page_logo, ACCESS_ANONYMOUS); + webui_static_content("/static", "src/webui/static"); webui_static_content("/docs", "docs/html"); webui_static_content("/docresources", "docs/docresources"); diff --git a/src/webui/webui.h b/src/webui/webui.h index cbbec569..0d50b554 100644 --- a/src/webui/webui.h +++ b/src/webui/webui.h @@ -20,6 +20,7 @@ #define WEBUI_H_ #include "htsmsg.h" +#include "http.h" void webui_init(void); @@ -30,6 +31,8 @@ void extjs_start(void); size_t html_escaped_len(const char *src); const char* html_escape(char *dst, const char *src, size_t len); +int page_static_file(http_connection_t *hc, const char *remain, void *opaque); + #if ENABLE_LINUXDVB void extjs_list_dvb_adapters(htsmsg_t *array); void extjs_start_dvb(void); @@ -54,5 +57,4 @@ void comet_mailbox_add_message(htsmsg_t *m, int isdebug); void comet_flush(void); - #endif /* WEBUI_H_ */