channel: added support for getting icons from underlying services

Also added an initial implementation of picon support.
This commit is contained in:
Adam Sutton 2014-05-17 00:04:03 +01:00 committed by Jaroslav Kysela
parent ab8af7c990
commit 0b3fcdce58
13 changed files with 182 additions and 66 deletions

View file

@ -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 *

View file

@ -29,6 +29,7 @@
#include <string.h>
#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
* *************************************************************************/

View file

@ -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);
}

View file

@ -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__ */

View file

@ -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;
}

View file

@ -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);
}
}

View file

@ -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__ */

View file

@ -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);

View file

@ -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

View file

@ -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__

View file

@ -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();

View file

@ -75,7 +75,7 @@ dumpchannels(htsbuf_queue_t *hq)
ch->ch_refcount,
ch->ch_zombie,
chbuf,
ch->ch_icon ?: "<none set>");
channel_get_icon(ch) ?: "<none set>");
}
}

View file

@ -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];