Also added an initial implementation of picon support.
#include <string.h>
#include "settings.h"
+#include "config.h"
#include "tvheadend.h"
#include "epg.h"
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 *
},
{
.type = PT_STR,
- .id = "icon",
- .name = "Icon",
- .off = offsetof(channel_t, ch_icon),
+ .id = "usericon",
+ .name = "User Icon",
+ .off = offsetof(channel_t, ch_usericon),
.notify = channel_class_icon_notify,
},
{
.type = PT_STR,
- .id = "icon_public_url",
- .name = "Icon URL",
- .get = channel_class_get_imagecache,
+ .id = "icon",
+ .name = "Icon",
+ .get = channel_class_get_icon,
.opts = PO_RDONLY | PO_NOSAVE | PO_HIDDEN,
},
{
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_usericon;
+ 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_usericon = strdup(icon);
+ channel_save(ch);
+ idnode_updated(&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
* *************************************************************************/
RB_REMOVE(&channels, ch, ch_link);
idnode_unlink(&ch->ch_id);
free(ch->ch_name);
- free(ch->ch_icon);
+ free(ch->ch_usericon);
free(ch);
}
/* Channel info */
char *ch_name; // Note: do not access directly!
int ch_number;
- char *ch_icon;
+ char *ch_usericon;
struct channel_tag_mapping_list ch_ctms;
/* Service/subscriptions */
}
/*
- * v3 -> v4 : fix broken DVB network / mux files
+ * v4 -> v5 : fix broken DVB network / mux files
*/
static void
config_migrate_v5 ( void )
}
}
+/*
+ * v5 -> v6 : change channel icon param
+ */
+static void
+config_migrate_v6 ( void )
+{
+ htsmsg_t *c, *e;
+ htsmsg_field_t *f;
+ const char *str;
+
+ /* Remove linux prefix from class */
+ if ((c = hts_settings_load_r(1, "channel"))) {
+ HTSMSG_FOREACH(f, c) {
+ if (!(e = htsmsg_field_get_map(f))) continue;
+ if (!(str = htsmsg_get_str(e, "icon"))) continue;
+ htsmsg_add_str(e, "usericon", str);
+ htsmsg_delete_field(e, "icon");
+ hts_settings_save(e, "channel/%s", f->hmf_name);
+ }
+ }
+}
+
/*
* Migration table
*/
config_migrate_v2,
config_migrate_v3,
config_migrate_v3, // Re-run due to bug in previous version of function
- config_migrate_v5
+ config_migrate_v5,
+ config_migrate_v6,
};
/*
{
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);
+}
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__ */
channel_tag_t *ct;
service_t *t;
epg_broadcast_t *now, *next = NULL;
+ const char *icon;
htsmsg_t *out = htsmsg_create_map();
htsmsg_t *tags = htsmsg_create_list();
htsmsg_add_u32(out, "channelNumber", channel_get_number(ch));
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);
}
}
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__ */
#include "input.h"
#include "settings.h"
#include "dvb_charset.h"
+#include "config.h"
/* **************************************************************************
* Class definition
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 )
{
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);
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
int (*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
const char *service_get_channel_name (service_t *s);
int service_get_channel_number (service_t *s);
+const char *service_get_channel_icon (service_t *s);
#endif // SERVICE_H__
htsmsg_add_str(m, "channel", channel_get_name(ch));
htsmsg_add_u32(m, "channelid", channel_get_id(ch));
- if(ch->ch_icon != NULL)
- htsmsg_add_imageurl(m, "chicon", "imagecache/%d", ch->ch_icon);
+ if ((s = channel_get_icon(ch)))
+ htsmsg_add_str(m, "chicon", s);
if((s = epg_episode_get_title(ee, lang)))
htsmsg_add_str(m, "title", s);
m = htsmsg_create_map();
htsmsg_add_u32(m, "id", ebc->id);
htsmsg_add_str(m, "channel", channel_get_name(ch));
- if (ch->ch_icon)
- htsmsg_add_imageurl(m, "chicon", "imagecache/%d", ch->ch_icon);
+ if ((s = channel_get_icon(ch)))
+ htsmsg_add_str(m, "chicon", s);
htsmsg_add_u32(m, "start", ebc->start);
htsmsg_add_msg(array, NULL, m);
}
htsmsg_add_str(m, "channel", DVR_CH_NAME(de));
if(de->de_channel != NULL) {
htsmsg_add_str(m, "channelid", channel_get_uuid(de->de_channel));
- if (de->de_channel->ch_icon)
- htsmsg_add_imageurl(m, "chicon", "imagecache/%d",
- de->de_channel->ch_icon);
+ if ((s = channel_get_icon(de->de_channel)))
+ htsmsg_add_str(m, "chicon", s);
}
htsmsg_add_str(m, "config_name", de->de_config_name);
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();
ch->ch_refcount,
ch->ch_zombie,
channel_get_number(ch),
- ch->ch_icon ?: "<none set>");
+ channel_get_icon(ch) ?: "<none set>");
}
}
[
'muxconfpath', 'language',
'tvhtime_update_enabled', 'tvhtime_ntp_enabled',
- 'tvhtime_tolerance', 'transcoding_enabled'
+ 'tvhtime_tolerance', 'transcoding_enabled',
+ 'piconpath'
]);
/* ****************************************************************
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
*/
layout: 'form',
defaultType: 'textfield',
autoHeight: true,
- items: [languageWrap, dvbscanWrap, tvhtimePanel, transcodingPanel]
+ items: [languageWrap, dvbscanWrap, tvhtimePanel, transcodingPanel, piconPanel]
});
var _items = [confpanel];