From 0b3fcdce580187227bc9f305b03f34d521c7300b Mon Sep 17 00:00:00 2001 From: Adam Sutton Date: Sat, 17 May 2014 00:04:03 +0100 Subject: [PATCH] channel: added support for getting icons from underlying services Also added an initial implementation of picon support. --- src/api/api_epg.c | 5 ++- src/channels.c | 75 ++++++++++++++++++++++--------- src/config.c | 10 +++++ src/config.h | 4 ++ src/dvr/dvr_db.c | 10 +---- src/htsp_server.c | 40 ++++++++--------- src/imagecache.h | 12 ----- src/input/mpegts/mpegts_service.c | 51 +++++++++++++++++++++ src/service.c | 11 +++++ src/service.h | 2 + src/webui/extjs.c | 2 + src/webui/statedump.c | 2 +- src/webui/static/app/config.js | 24 +++++++++- 13 files changed, 182 insertions(+), 66 deletions(-) diff --git a/src/api/api_epg.c b/src/api/api_epg.c index 23f48297..6d8d05a1 100644 --- a/src/api/api_epg.c +++ b/src/api/api_epg.c @@ -53,6 +53,7 @@ api_epg_add_channel ( htsmsg_t *m, channel_t *ch ) { int64_t chnum; char buf[32]; + const char *s; htsmsg_add_str(m, "channelName", channel_get_name(ch)); htsmsg_add_str(m, "channelUuid", channel_get_uuid(ch)); if ((chnum = channel_get_number(ch)) >= 0) { @@ -64,8 +65,8 @@ api_epg_add_channel ( htsmsg_t *m, channel_t *ch ) snprintf(buf, sizeof(buf), "%u", maj); htsmsg_add_str(m, "channelNumber", buf); } - if (ch->ch_icon) - htsmsg_add_imageurl(m, "channelIcon", "imagecache/%d", ch->ch_icon); + if ((s = channel_get_icon(ch)) != NULL) + htsmsg_add_str(m, "channelIcon", s); } static htsmsg_t * diff --git a/src/channels.c b/src/channels.c index 084f9c5d..a8357f67 100644 --- a/src/channels.c +++ b/src/channels.c @@ -29,6 +29,7 @@ #include #include "settings.h" +#include "config.h" #include "tvheadend.h" #include "epg.h" @@ -166,29 +167,15 @@ channel_class_tags_set ( void *obj, const void *p ) static void channel_class_icon_notify ( void *obj ) { - channel_t *ch = obj; - if (ch->ch_icon) - imagecache_get_id(ch->ch_icon); + (void)channel_get_icon(obj); } static const void * -channel_class_get_imagecache ( void *obj ) +channel_class_get_icon ( void *obj ) { - static char buf[512], *r; - uint32_t id; - channel_t *ch = obj; - - if (!ch->ch_icon) { - r = NULL; - } else if ((id = imagecache_get_id(ch->ch_icon))) { - snprintf(buf, sizeof(buf), "imagecache/%d", id); - r = buf; - } else { - strncpy(buf, ch->ch_icon, sizeof(buf)); - r = buf; - } - - return &r; + static const char *s; + s = channel_get_icon(obj); + return &s; } static const char * @@ -317,7 +304,7 @@ const idclass_t channel_class = { { .type = PT_STR, .id = "icon", - .name = "Icon", + .name = "User Icon", .off = offsetof(channel_t, ch_icon), .notify = channel_class_icon_notify, }, @@ -325,7 +312,7 @@ const idclass_t channel_class = { .type = PT_STR, .id = "icon_public_url", .name = "Icon URL", - .get = channel_class_get_imagecache, + .get = channel_class_get_icon, .opts = PO_RDONLY | PO_NOSAVE | PO_HIDDEN, }, { @@ -545,6 +532,52 @@ channel_get_number ( channel_t *ch ) return 0; } +const char * +channel_get_icon ( channel_t *ch ) +{ + static __thread char buf[512], buf2[512]; + channel_service_mapping_t *csm; + const char *picon = config_get_picon_path(), + *icon = ch->ch_icon; + uint32_t id; + + /* No user icon - try access from services */ + if (!icon && picon) { + LIST_FOREACH(csm, &ch->ch_services, csm_chn_link) { + if (!(icon = service_get_channel_icon(csm->csm_svc))) continue; + if (strncmp(icon, "picon://", 8)) { + icon = NULL; + continue; + } + sprintf(buf2, "%s/%s", picon, icon+8); + ch->ch_icon = strdup(icon); + channel_save(ch); + idnode_notify_simple(&ch->ch_id); + } + } + + /* Nothing */ + if (!icon || !*icon) + return NULL; + + /* Picon? */ + if (!strncmp(icon, "picon://", 8)) { + if (!picon) return NULL; + sprintf(buf2, "%s/%s", picon, icon+8); + icon = buf2; + } + + /* Lookup imagecache ID */ + if ((id = imagecache_get_id(icon))) { + snprintf(buf, sizeof(buf), "imagecache/%d", id); + + } else { + strncpy(buf, icon, sizeof(buf)); + } + + return buf; +} + /* ************************************************************************** * Creation/Deletion * *************************************************************************/ diff --git a/src/config.c b/src/config.c index 81d34ff0..900ec2e4 100644 --- a/src/config.c +++ b/src/config.c @@ -1303,3 +1303,13 @@ int config_set_muxconfpath ( const char *path ) { return _config_set_str("muxconfpath", path); } + +const char *config_get_picon_path ( void ) +{ + return htsmsg_get_str(config, "piconpath"); +} + +int config_set_picon_path ( const char *str ) +{ + return _config_set_str("piconpath", str); +} diff --git a/src/config.h b/src/config.h index 9f08a672..76f054e4 100644 --- a/src/config.h +++ b/src/config.h @@ -37,4 +37,8 @@ const char *config_get_language ( void ); int config_set_language ( const char *str ) __attribute__((warn_unused_result)); +const char *config_get_picon_path ( void ); +int config_set_picon_path ( const char *str ) + __attribute__((warn_unused_result)); + #endif /* __TVH_CONFIG__H__ */ diff --git a/src/dvr/dvr_db.c b/src/dvr/dvr_db.c index 5e7427ad..ff78b258 100644 --- a/src/dvr/dvr_db.c +++ b/src/dvr/dvr_db.c @@ -1586,17 +1586,11 @@ dvr_entry_class_channel_icon_url_get(void *o) dvr_entry_t *de = (dvr_entry_t *)o; channel_t *ch = de->de_channel; static const char *s; - static char buf[256]; - uint32_t id; if (ch == NULL) { s = ""; - } else if ((id = imagecache_get_id(ch->ch_icon)) != 0) { - snprintf(buf, sizeof(buf), "imagecache/%d", id); - } else { - strncpy(buf, ch->ch_icon ?: "", sizeof(buf)); - buf[sizeof(buf)-1] = '\0'; + } else if ((s = channel_get_icon(ch)) == NULL) { + s = ""; } - s = buf; return &s; } diff --git a/src/htsp_server.c b/src/htsp_server.c index c78b6ab2..a6a3fc6f 100644 --- a/src/htsp_server.c +++ b/src/htsp_server.c @@ -551,6 +551,7 @@ htsp_build_channel(channel_t *ch, const char *method, htsp_connection_t *htsp) service_t *t; epg_broadcast_t *now, *next = NULL; int64_t chnum = channel_get_number(ch); + const char *icon; htsmsg_t *out = htsmsg_create_map(); htsmsg_t *tags = htsmsg_create_list(); @@ -562,31 +563,30 @@ htsp_build_channel(channel_t *ch, const char *method, htsp_connection_t *htsp) htsmsg_add_u32(out, "channelNumberMinor", channel_get_minor(chnum)); htsmsg_add_str(out, "channelName", channel_get_name(ch)); - if(ch->ch_icon != NULL) { - uint32_t id; - struct sockaddr_storage addr; - socklen_t addrlen; - if ((id = imagecache_get_id(ch->ch_icon))) { + if ((icon = channel_get_icon(ch))) { + + /* Handle older clients */ + if ((strstr(icon, "imagecache") == icon) && htsp->htsp_version < 8) { + struct sockaddr_storage addr; + socklen_t addrlen; size_t p = 0; char url[256]; char buf[50]; - if (htsp->htsp_version < 8) { - addrlen = sizeof(addr); - getsockname(htsp->htsp_fd, (struct sockaddr*)&addr, &addrlen); - tcp_get_ip_str((struct sockaddr*)&addr, buf, 50); - strcpy(url, "http://"); - p = strlen(url); - p += snprintf(url+p, sizeof(url)-p, "%s%s%s:%d%s", - (addr.ss_family == AF_INET6)?"[":"", - buf, - (addr.ss_family == AF_INET6)?"]":"", - tvheadend_webui_port, - tvheadend_webroot ?: ""); - } - snprintf(url+p, sizeof(url)-p, "/imagecache/%d", id); + addrlen = sizeof(addr); + getsockname(htsp->htsp_fd, (struct sockaddr*)&addr, &addrlen); + tcp_get_ip_str((struct sockaddr*)&addr, buf, 50); + strcpy(url, "http://"); + p = strlen(url); + p += snprintf(url+p, sizeof(url)-p, "%s%s%s:%d%s", + (addr.ss_family == AF_INET6)?"[":"", + buf, + (addr.ss_family == AF_INET6)?"]":"", + tvheadend_webui_port, + tvheadend_webroot ?: ""); + snprintf(url+p, sizeof(url)-p, "/%s", icon); htsmsg_add_str(out, "channelIcon", url); } else { - htsmsg_add_str(out, "channelIcon", ch->ch_icon); + htsmsg_add_str(out, "channelIcon", icon); } } diff --git a/src/imagecache.h b/src/imagecache.h index 7b410877..a2afa313 100644 --- a/src/imagecache.h +++ b/src/imagecache.h @@ -45,16 +45,4 @@ 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);\ - htsmsg_add_str(_msg, _fld, _tmp);\ - } else {\ - htsmsg_add_str(_msg, _fld, _url);\ - }\ - } - #endif /* __IMAGE_CACHE_H__ */ diff --git a/src/input/mpegts/mpegts_service.c b/src/input/mpegts/mpegts_service.c index e0959257..59755f50 100644 --- a/src/input/mpegts/mpegts_service.c +++ b/src/input/mpegts/mpegts_service.c @@ -24,6 +24,7 @@ #include "input.h" #include "settings.h" #include "dvb_charset.h" +#include "config.h" /* ************************************************************************** * Class definition @@ -394,6 +395,55 @@ mpegts_service_provider_name ( service_t *s ) return ((mpegts_service_t*)s)->s_dvb_provider; } +static const char * +mpegts_service_channel_icon ( service_t *s ) +{ + mpegts_service_t *ms = (mpegts_service_t*)s; + + /* DVB? */ +#if ENABLE_MPEGTS_DVB + extern const idclass_t dvb_mux_class; + if (ms->s_dvb_mux && + idnode_is_instance(&ms->s_dvb_mux->mm_id, &dvb_mux_class)) { + int32_t hash = 0; + static __thread char buf[1024]; + dvb_mux_t *mmd = (dvb_mux_t*)ms->s_dvb_mux; + + switch ( mmd->lm_tuning.dmc_fe_type) { + case DVB_TYPE_S: + if (mmd->lm_tuning.u.dmc_fe_qpsk.orbital_dir == 'E') + hash = mmd->lm_tuning.u.dmc_fe_qpsk.orbital_pos; + else + hash = 0xFFFF - mmd->lm_tuning.u.dmc_fe_qpsk.orbital_pos; + hash <<= 16; + break; + case DVB_TYPE_C: + hash = 0xFFFF0000; + break; + case DVB_TYPE_T: + hash = 0xEEEE0000; + break; + case DVB_TYPE_ATSC: + hash = 0xDDDD0000; + break; + default: + return NULL; + } + + snprintf(buf, sizeof(buf), + "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; + } +#endif + + return NULL; +} + void mpegts_service_delete ( service_t *t, int delconf ) { @@ -459,6 +509,7 @@ mpegts_service_create0 s->s_channel_number = mpegts_service_channel_number; s->s_channel_name = mpegts_service_channel_name; s->s_provider_name = mpegts_service_provider_name; + s->s_channel_icon = mpegts_service_channel_icon; pthread_mutex_lock(&s->s_stream_mutex); service_make_nicename((service_t*)s); diff --git a/src/service.c b/src/service.c index 8de4dfb3..23aab503 100644 --- a/src/service.c +++ b/src/service.c @@ -1561,6 +1561,17 @@ service_get_channel_number ( service_t *s ) return 0; } +/* + * Get name for channel from service + */ +const char * +service_get_channel_icon ( service_t *s ) +{ + const char *r = NULL; + if (s->s_channel_icon) r = s->s_channel_icon(s); + return r; +} + /** * Get the encryption CAID from a service * only the first CA stream in a service is returned diff --git a/src/service.h b/src/service.h index b6d56ac3..2aee0e3b 100644 --- a/src/service.h +++ b/src/service.h @@ -295,6 +295,7 @@ typedef struct service { int64_t (*s_channel_number) (struct service *); const char *(*s_channel_name) (struct service *); const char *(*s_provider_name) (struct service *); + const char *(*s_channel_icon) (struct service *); /** * Name usable for displaying to user @@ -565,5 +566,6 @@ void sort_elementary_streams(service_t *t); const char *service_get_channel_name (service_t *s); const char *service_get_full_channel_name (service_t *s); int64_t service_get_channel_number (service_t *s); +const char *service_get_channel_icon (service_t *s); #endif // SERVICE_H__ diff --git a/src/webui/extjs.c b/src/webui/extjs.c index ce4e4385..be2c742c 100755 --- a/src/webui/extjs.c +++ b/src/webui/extjs.c @@ -511,6 +511,8 @@ 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); + if ((str = http_arg_get(&hc->hc_req_args, "piconpath"))) + save |= config_set_picon_path(str); if (save) config_save(); diff --git a/src/webui/statedump.c b/src/webui/statedump.c index db74cd55..86379521 100644 --- a/src/webui/statedump.c +++ b/src/webui/statedump.c @@ -75,7 +75,7 @@ dumpchannels(htsbuf_queue_t *hq) ch->ch_refcount, ch->ch_zombie, chbuf, - ch->ch_icon ?: ""); + channel_get_icon(ch) ?: ""); } } diff --git a/src/webui/static/app/config.js b/src/webui/static/app/config.js index 04daff73..a7c2c38b 100644 --- a/src/webui/static/app/config.js +++ b/src/webui/static/app/config.js @@ -43,7 +43,8 @@ tvheadend.miscconf = function(panel, index) { [ 'muxconfpath', 'language', 'tvhtime_update_enabled', 'tvhtime_ntp_enabled', - 'tvhtime_tolerance', 'transcoding_enabled' + 'tvhtime_tolerance', 'transcoding_enabled', + 'piconpath' ]); /* **************************************************************** @@ -126,6 +127,25 @@ tvheadend.miscconf = function(panel, index) { items: [tvhtimeUpdateEnabled, tvhtimeNtpEnabled, tvhtimeTolerance] }); + /* + * Picons + */ + + var piconPath = new Ext.form.TextField({ + name: 'piconpath', + fieldLabel: 'Picon path (e.g. file:///tmp/picons)', + width: 400 + }); + + var piconPanel = new Ext.form.FieldSet({ + title: 'Picon', + width: 700, + autoHeight: true, + collapsible: true, + animCollapse: true, + items: [piconPath] + }); + /* * Image cache */ @@ -232,7 +252,7 @@ tvheadend.miscconf = function(panel, index) { layout: 'form', defaultType: 'textfield', autoHeight: true, - items: [languageWrap, dvbscanWrap, tvhtimePanel, transcodingPanel] + items: [languageWrap, dvbscanWrap, tvhtimePanel, transcodingPanel, piconPanel] }); var _items = [confpanel];