"dvbscan:yes"
"timeshift:yes"
"trace:yes"
- "imagecache:auto"
"avahi:auto"
"zlib:auto"
"libav:auto"
fi
fi
-#
-# Icon caching
-#
-if enabled_or_auto imagecache; then
- enable imagecache
-fi
-
#
# DVB scan
#
api_epg_add_channel ( htsmsg_t *m, channel_t *ch, const char *blank )
{
int64_t chnum;
- char buf[32];
+ char buf[128];
const char *s;
htsmsg_add_str(m, "channelName", channel_get_name(ch, blank));
htsmsg_add_uuid(m, "channelUuid", &ch->ch_id.in_uuid);
snprintf(buf, sizeof(buf), "%u", maj);
htsmsg_add_str(m, "channelNumber", buf);
}
- if ((s = channel_get_icon(ch)) != NULL)
- htsmsg_add_str(m, "channelIcon", s);
+ s = channel_get_icon(ch);
+ if (!strempty(s)) {
+ s = imagecache_get_propstr(s, buf, sizeof(buf));
+ if (s)
+ htsmsg_add_str(m, "channelIcon", s);
+ }
}
static htsmsg_t *
api_epg_entry ( epg_broadcast_t *eb, const char *lang, const access_t *perm, const char **blank )
{
const char *s, *blank2 = NULL;
- char buf[64];
- channel_t *ch = eb->channel;
+ char buf[32];
+ channel_t *ch = eb->channel;
htsmsg_t *m, *m2;
epg_episode_num_t epnum;
epg_genre_t *eg;
htsmsg_add_str(m, "episodeOnscreen", buf);
/* Image */
- if (eb->image)
- htsmsg_add_str(m, "image", eb->image);
+ s = eb->image;
+ if (!strempty(s)) {
+ s = imagecache_get_propstr(s, buf, sizeof(buf));
+ if (s)
+ htsmsg_add_str(m, "image", s);
+ }
/* Rating */
if (eb->star_rating)
#include "api.h"
#include "imagecache.h"
-#if ENABLE_IMAGECACHE
-
static int
api_imagecache_clean
( access_t *perm, void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
api_register_all(ah);
}
-
-#else /* ENABLE_IMAGECACHE */
-
-void
-api_imagecache_init ( void )
-{
-}
-
-#endif
return channel_get_id(a) - channel_get_id(b);
}
+static void
+channel_load_icon ( channel_t *ch )
+{
+ (void)imagecache_get_id(channel_get_icon(ch));
+}
+
+static void
+channel_tag_load_icon ( channel_tag_t *tag )
+{
+ (void)imagecache_get_id(channel_tag_get_icon(tag));
+}
+
/* **************************************************************************
* Class definition
* *************************************************************************/
{
channel_t *ch = obj;
if (!ch->ch_load)
- (void)channel_get_icon(obj);
+ channel_load_icon(obj);
}
-static const void *
+const void *
channel_class_get_icon ( void *obj )
{
prop_ptr = channel_get_icon(obj);
+ if (!strempty(prop_ptr))
+ prop_ptr = imagecache_get_propstr(prop_ptr, prop_sbuf, PROP_SBUF_LEN);
return &prop_ptr;
}
*picon = config.picon_path,
*icon = ch->ch_icon,
*chname, *icn;
- int id, i, pick, prefer = config.prefer_picon ? 1 : 0;
+ int i, pick, prefer = config.prefer_picon ? 1 : 0;
char c;
if (tvh_str_default(icon, NULL) == NULL)
icon = buf2;
}
- /* Lookup imagecache ID */
- if ((id = imagecache_get_id(icon))) {
- snprintf(buf, sizeof(buf), "imagecache/%d", id);
- } else {
- strlcpy(buf, icon, sizeof(buf));
- }
-
- return buf;
+ return icon;
}
int channel_set_icon ( channel_t *ch, const char *icon )
htsp_channel_add(ch);
/* determine icon URL */
- (void)channel_get_icon(ch);
+ channel_load_icon(ch);
return ch;
}
const char *
channel_tag_get_icon(channel_tag_t *ct)
{
- static char buf[64];
- const char *icon = ct->ct_icon;
- int id;
-
- /* Lookup imagecache ID */
- if ((id = imagecache_get_id(icon))) {
- snprintf(buf, sizeof(buf), "imagecache/%d", id);
- return buf;
- }
- return icon;
+ return ct->ct_icon;
}
/**
static void
channel_tag_class_icon_notify ( void *obj, const char *lang )
{
- (void)channel_tag_get_icon(obj);
+ channel_tag_load_icon(obj);
}
static const void *
channel_tag_class_get_icon ( void *obj )
{
prop_ptr = channel_tag_get_icon(obj);
+ if (!strempty(prop_ptr))
+ prop_ptr = imagecache_get_propstr(prop_ptr, prop_sbuf, PROP_SBUF_LEN);
return &prop_ptr;
}
htsmsg_t * channel_class_get_list(void *o, const char *lang);
+const void * channel_class_get_icon ( void *obj );
+
int channel_set_tags_by_list ( channel_t *ch, htsmsg_t *tags );
channel_tag_t *channel_tag_create(const char *uuid, htsmsg_t *conf);
htsmsg_t * dvr_autorec_entry_class_weekdays_get(uint32_t weekdays);
htsmsg_t * dvr_autorec_entry_class_weekdays_list (void *o, const char *list);
char * dvr_autorec_entry_class_weekdays_rend(uint32_t weekdays, const char *lang);
-const char *dvr_entry_class_image_url_get(const dvr_entry_t *o);
+const char *dvr_entry_get_image(const dvr_entry_t *o);
+const char *dvr_entry_get_fanart_image(const dvr_entry_t *o);
void dvr_autorec_check_event(epg_broadcast_t *e);
dvr_entry_t *de = (dvr_entry_t *)o;
channel_t *ch = de->de_channel;
if (ch == NULL) {
- prop_ptr = NULL;
+ prop_ptr = "";
} else {
- prop_ptr = channel_get_icon(ch);
+ return channel_class_get_icon(ch);
}
+ return &prop_ptr;
+}
+
+const char *
+dvr_entry_get_image(const dvr_entry_t *de)
+{
+ if (de->de_bcast && de->de_bcast && de->de_bcast->image)
+ return de->de_bcast->image;
+ if (de->de_image)
+ return de->de_image;
+ return NULL;
+}
+
+const char *
+dvr_entry_get_fanart_image(const dvr_entry_t *de)
+{
+ return de->de_fanart_image;
+}
+
+static const void *
+dvr_entry_class_image_get0(dvr_entry_t *de, const char *image)
+{
+ prop_ptr = imagecache_get_propstr(image, prop_sbuf, PROP_SBUF_LEN);
if (prop_ptr == NULL)
prop_ptr = "";
return &prop_ptr;
}
static const void *
-dvr_entry_class_image_url_get_as_property(void *o)
+dvr_entry_class_image_get(void *o)
{
- dvr_entry_t *de = (dvr_entry_t *)o;
- static const char *s = "";
- /* We prefer the image from the broadcast to the one currently
- * persisted. This is because a programme scheduled far in the
- * future may have a generic image that will be updated nearer the
- * broadcast date with a more specific image.
- */
- if (de->de_bcast && de->de_bcast && de->de_bcast->image) {
- snprintf(prop_sbuf, PROP_SBUF_LEN, "%s", de->de_bcast->image);
- return &prop_sbuf_ptr;
- }
-
- if (de->de_image) {
- prop_ptr = de->de_image;
- return &prop_ptr;
- }
-
- return &s;
+ return dvr_entry_class_image_get0(o, dvr_entry_get_image(o));
}
-const char *
-dvr_entry_class_image_url_get(const dvr_entry_t *o)
+static void
+dvr_entry_class_image_notify(void *o, const char *lang)
{
- const void *image = dvr_entry_class_image_url_get_as_property((void*)o);
- if (!image) return NULL;
- const char *image_str = *(const char**)image;
- if (!image_str) return NULL;
- if (!*image_str) return NULL;
- return image_str;
+ (void)imagecache_get_id(dvr_entry_get_image(o));
}
+static const void *
+dvr_entry_class_fanart_image_get(void *o)
+{
+ return dvr_entry_class_image_get0(o, dvr_entry_get_fanart_image(o));
+}
+static void
+dvr_entry_class_fanart_image_notify(void *o, const char *lang)
+{
+ (void)imagecache_get_id(dvr_entry_get_fanart_image(o));
+}
static const void *
dvr_entry_class_duplicate_get(void *o)
.id = "image", /* Name chosen to be compatible with api_epg */
.name = N_("Episode image"),
.desc = N_("Episode image."),
- .get = dvr_entry_class_image_url_get_as_property,
+ .get = dvr_entry_class_image_get,
+ .notify = dvr_entry_class_image_notify,
.off = offsetof(dvr_entry_t, de_image),
.opts = PO_HIDDEN,
},
.id = "fanart_image",
.name = N_("Fanart image"),
.desc = N_("Fanart image."),
+ .get = dvr_entry_class_fanart_image_get,
+ .notify = dvr_entry_class_fanart_image_notify,
.off = offsetof(dvr_entry_t, de_fanart_image),
.opts = PO_HIDDEN,
},
#define HTSP_ASYNC_ON 0x01
#define HTSP_ASYNC_EPG 0x02
-#define HTSP_ASYNC_AUX_CH 0x01
-#define HTSP_ASYNC_AUX_CHTAG 0x02
-#define HTSP_ASYNC_AUX_CHTAG_DEL 0x03
-#define HTSP_ASYNC_AUX_DVR 0x04
-#define HTSP_ASYNC_AUX_AUTOREC 0x05
-#define HTSP_ASYNC_AUX_TIMEREC 0x06
-#define HTSP_ASYNC_AUX_EPG 0x07
-
#define HTSP_ASYNC_EPG_INTERVAL 30
#define HTSP_PRIV_MASK (ACCESS_HTSP_STREAMING)
tvh_mutex_unlock(&htsp->htsp_out_mutex);
}
+/*
+ *
+ */
+static const char *
+htsp_image(htsp_connection_t *htsp, const char *image, char *buf, size_t buflen)
+{
+ const char *ret = image;
+ const int id = imagecache_get_id(image);
+
+ /* Handle older clients */
+ if (id) {
+ if (htsp->htsp_version < 8) {
+ struct sockaddr_storage addr;
+ socklen_t addrlen;
+ char abuf[50];
+ addrlen = sizeof(addr);
+ getsockname(htsp->htsp_fd, (struct sockaddr*)&addr, &addrlen);
+ tcp_get_str_from_ip(&addr, abuf, sizeof(abuf));
+ snprintf(buf, buflen, "http://%s%s%s:%d%s/imagecache/%d",
+ (addr.ss_family == AF_INET6)?"[":"",
+ abuf,
+ (addr.ss_family == AF_INET6)?"]":"",
+ tvheadend_webui_port,
+ tvheadend_webroot ?: "",
+ id);
+ ret = buf;
+ } else if (htsp->htsp_version < 15) {
+ /* older clients expects '/imagecache/' */
+ snprintf(buf, buflen, "/imagecache/%d", id);
+ ret = buf;
+ } else {
+ snprintf(buf, buflen, "imagecache/%d", id);
+ ret = buf;
+ }
+ }
+ return ret;
+}
+
/**
*
*/
epg_broadcast_t *now, *next = NULL;
int64_t chnum = channel_get_number(ch);
const char *icon;
- char buf[64];
+ char buf[512];
htsmsg_t *out = htsmsg_create_map();
htsmsg_t *tags = htsmsg_create_list();
htsmsg_add_u32(out, "channelNumberMinor", channel_get_minor(chnum));
htsmsg_add_str(out, "channelName", channel_get_name(ch, channel_blank_name));
- 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;
- char url[256];
- char buf[50];
- addrlen = sizeof(addr);
- getsockname(htsp->htsp_fd, (struct sockaddr*)&addr, &addrlen);
- tcp_get_str_from_ip(&addr, buf, 50);
- snprintf(url, sizeof(url), "http://%s%s%s:%d%s/%s",
- (addr.ss_family == AF_INET6)?"[":"",
- buf,
- (addr.ss_family == AF_INET6)?"]":"",
- tvheadend_webui_port,
- tvheadend_webroot ?: "",
- icon);
- htsmsg_add_str(out, "channelIcon", url);
- } else {
- if (htsp->htsp_version < 15) {
- /* older clients expects '/imagecache/' */
- if (strncmp(icon, "imagecache/", 11) == 0) {
- snprintf(buf, sizeof(buf), "/%s", icon);
- icon = buf;
- }
- }
- htsmsg_add_str(out, "channelIcon", icon);
- }
- }
+ if ((icon = channel_get_icon(ch)))
+ htsmsg_add_str(out, "channelIcon", htsp_image(htsp, icon, buf, sizeof(buf)));
now = ch->ch_epg_now;
next = ch->ch_epg_next;
*
*/
static htsmsg_t *
-htsp_build_tag(channel_tag_t *ct, const char *method, int include_channels)
+htsp_build_tag(htsp_connection_t *htsp, channel_tag_t *ct, const char *method, int include_channels)
{
+ char buf[512];
+ const char *icon;
idnode_list_mapping_t *ilm;
htsmsg_t *out = htsmsg_create_map();
htsmsg_t *members = include_channels ? htsmsg_create_list() : NULL;
htsmsg_add_u32(out, "tagIndex", ct->ct_index);
htsmsg_add_str(out, "tagName", ct->ct_name);
- htsmsg_add_str(out, "tagIcon", channel_tag_get_icon(ct));
+ icon = channel_tag_get_icon(ct);
+ if (!strempty(icon))
+ htsmsg_add_str(out, "tagIcon", htsp_image(htsp, icon, buf, sizeof(buf)));
htsmsg_add_u32(out, "tagTitledIcon", ct->ct_titled_icon);
if(members != NULL) {
const char *p, *last;
int64_t fsize = -1, start, stop;
uint32_t u32;
+ char buf[512];
char ubuf[UUID_HEX_SIZE];
htsmsg_add_u32(out, "id", idnode_get_short_uuid(&de->de_id));
* an image from current EPG if recording does not have
* an associated image.
*/
- const char *image = dvr_entry_class_image_url_get(de);
- if(image && *image)
- htsmsg_add_str(out, "image", image);
+ const char *image = dvr_entry_get_image(de);
+ if(!strempty(image))
+ htsmsg_add_str(out, "image", htsp_image(htsp, image, buf, sizeof(buf)));
/* htsmsg camelcase to be compatible with other names */
image = de->de_fanart_image;
- if(image && *image)
- htsmsg_add_str(out, "fanartImage", image);
+ if(!strempty(image))
+ htsmsg_add_str(out, "fanartImage", htsp_image(htsp, image, buf, sizeof(buf)));
if (de->de_copyright_year)
htsmsg_add_u32(out, "copyrightYear", de->de_copyright_year);
epg_genre_t *g;
epg_episode_num_t epnum;
const char *str;
+ char buf[512];
/* Ignore? */
if (update && e->updated <= update) return NULL;
htsmsg_add_s64(out, "firstAired", e->first_aired);
epg_broadcast_get_epnum(e, &epnum);
htsp_serialize_epnum(out, &epnum, NULL);
- if (e->image)
- htsmsg_add_str(out, "image", e->image);
+ if (!strempty(e->image))
+ htsmsg_add_str(out, "image", htsp_image(htsp, e->image, buf, sizeof(buf)));
if (e->channel) {
LIST_FOREACH(de, &e->channel->ch_dvrs, de_channel_link) {
/* Send all enabled and external tags */
TAILQ_FOREACH(ct, &channel_tags, ct_link)
if(channel_tag_access(ct, htsp->htsp_granted_access, 0))
- htsp_send_message(htsp, htsp_build_tag(ct, "tagAdd", 0), NULL);
+ htsp_send_message(htsp, htsp_build_tag(htsp, ct, "tagAdd", 0), NULL);
/* Send all channels */
CHANNEL_FOREACH(ch)
/* Send all enabled and external tags (now with channel mappings) */
TAILQ_FOREACH(ct, &channel_tags, ct_link)
if(channel_tag_access(ct, htsp->htsp_granted_access, 0))
- htsp_send_message(htsp, htsp_build_tag(ct, "tagUpdate", 1), NULL);
+ htsp_send_message(htsp, htsp_build_tag(htsp, ct, "tagUpdate", 1), NULL);
/* Send all autorecs */
TAILQ_FOREACH(dae, &autorec_entries, dae_link)
*
*/
static void
-htsp_async_send(htsmsg_t *m, int mode, int aux_type, void *aux)
+htsp_async_send(htsmsg_t *m, int mode, void *aux)
{
htsp_connection_t *htsp;
lock_assert(&global_lock);
LIST_FOREACH(htsp, &htsp_async_connections, htsp_async_link)
- if (htsp->htsp_async_mode & mode) {
- if (aux_type == HTSP_ASYNC_AUX_CHTAG &&
- !channel_tag_access(aux, htsp->htsp_granted_access, 0))
- continue;
+ if (htsp->htsp_async_mode & mode)
htsp_send_message(htsp, htsmsg_copy(m), NULL);
- }
htsmsg_destroy(m);
}
+/**
+ *
+ */
+typedef htsmsg_t *(*http_async_send_cb_t)(htsp_connection_t *htsp, void *aux);
+
+static void
+htsp_async_send_cb(http_async_send_cb_t cb, int mode, void *aux)
+{
+ htsp_connection_t *htsp;
+ htsmsg_t *m;
+
+ lock_assert(&global_lock);
+ LIST_FOREACH(htsp, &htsp_async_connections, htsp_async_link)
+ if (htsp->htsp_async_mode & mode) {
+ m = cb(htsp, aux);
+ if (m != NULL) {
+ htsp_send_message(htsp, m, NULL);
+ htsmsg_destroy(m);
+ }
+ }
+}
+
/**
* Called from channel.c when a new channel is created
*/
htsmsg_t *m = htsmsg_create_map();
htsmsg_add_u32(m, "channelId", channel_get_id(ch));
htsmsg_add_str(m, "method", "channelDelete");
- htsp_async_send(m, HTSP_ASYNC_ON, HTSP_ASYNC_AUX_CH, ch);
+ htsp_async_send(m, HTSP_ASYNC_ON, ch);
}
+/**
+ *
+ */
+static htsmsg_t *
+htsp_tag_update_msg(htsp_connection_t *htsp, void *tag)
+{
+ if (!channel_tag_access(tag, htsp->htsp_granted_access, 0))
+ return NULL;
+ return htsp_build_tag(htsp, tag, "tagUpdate", 1);
+}
/**
* Called from channel.c when a tag is exported
void
htsp_tag_add(channel_tag_t *ct)
{
- htsp_async_send(htsp_build_tag(ct, "tagAdd", 1), HTSP_ASYNC_ON,
- HTSP_ASYNC_AUX_CHTAG, ct);
+ htsp_async_send_cb(htsp_tag_update_msg, HTSP_ASYNC_ON, ct);
}
-
/**
* Called from channel.c when an exported tag is changed
*/
void
htsp_tag_update(channel_tag_t *ct)
{
- if (ct->ct_enabled && !ct->ct_internal) {
- htsp_async_send(htsp_build_tag(ct, "tagUpdate", 1), HTSP_ASYNC_ON,
- HTSP_ASYNC_AUX_CHTAG, ct);
- }
+ if (ct->ct_enabled && !ct->ct_internal)
+ htsp_async_send_cb(htsp_tag_update_msg, HTSP_ASYNC_ON, ct);
else // in case the tag was ever sent to the client
htsp_tag_delete(ct);
}
htsmsg_t *m = htsmsg_create_map();
htsmsg_add_u32(m, "tagId", htsp_channel_tag_get_identifier(ct));
htsmsg_add_str(m, "method", "tagDelete");
- htsp_async_send(m, HTSP_ASYNC_ON, HTSP_ASYNC_AUX_CHTAG_DEL, ct);
+ htsp_async_send(m, HTSP_ASYNC_ON, ct);
}
/**
_htsp_dvr_entry_update(de, "dvrEntryAdd", NULL);
}
-
/**
* Called from dvr_db.c when a DVR entry is updated
*/
}
}
-
/**
* Called from dvr_db.c when a DVR entry is deleted
*/
htsmsg_t *m = htsmsg_create_map();
htsmsg_add_u32(m, "id", idnode_get_short_uuid(&de->de_id));
htsmsg_add_str(m, "method", "dvrEntryDelete");
- htsp_async_send(m, HTSP_ASYNC_ON, HTSP_ASYNC_AUX_DVR, de);
+ htsp_async_send(m, HTSP_ASYNC_ON, de);
}
/**
htsmsg_t *m = htsmsg_create_map();
htsmsg_add_str(m, "id", idnode_uuid_as_str(&dae->dae_id, ubuf));
htsmsg_add_str(m, "method", "autorecEntryDelete");
- htsp_async_send(m, HTSP_ASYNC_ON, HTSP_ASYNC_AUX_AUTOREC, dae);
+ htsp_async_send(m, HTSP_ASYNC_ON, dae);
}
/**
htsmsg_t *m = htsmsg_create_map();
htsmsg_add_str(m, "id", idnode_uuid_as_str(&dte->dte_id, ubuf));
htsmsg_add_str(m, "method", "timerecEntryDelete");
- htsp_async_send(m, HTSP_ASYNC_ON, HTSP_ASYNC_AUX_TIMEREC, dte);
+ htsp_async_send(m, HTSP_ASYNC_ON, dte);
}
/**
htsmsg_t *m = htsmsg_create_map();
htsmsg_add_str(m, "method", "eventDelete");
htsmsg_add_u32(m, "eventId", ebc->id);
- htsp_async_send(m, HTSP_ASYNC_EPG, HTSP_ASYNC_AUX_EPG, ebc);
+ htsp_async_send(m, HTSP_ASYNC_EPG, ebc);
}
static const char frametypearray[PKT_NTYPES] = {
*
*/
char *
-http_get_hostpath(http_connection_t *hc)
+http_get_hostpath(http_connection_t *hc, char *buf, size_t buflen)
{
- char buf[256];
const char *host, *proto;
host = http_arg_get(&hc->hc_args, "Host") ?:
http_arg_get(&hc->hc_args, "X-Forwarded-Host");
proto = http_arg_get(&hc->hc_args, "X-Forwarded-Proto");
- snprintf(buf, sizeof(buf), "%s://%s%s",
+ snprintf(buf, buflen, "%s://%s%s",
proto ?: "http", host ?: "localhost", tvheadend_webroot ?: "");
- return strdup(buf);
+ return buf;
}
/**
void http_parse_args(http_arg_list_t *list, char *args);
-char *http_get_hostpath(http_connection_t *hc);
+char *http_get_hostpath(http_connection_t *hc, char *buf, size_t buflen);
/*
* HTTP/RTSP Client
{
int id; ///< Internal ID
const char *url; ///< Upstream URL
- int failed; ///< Last update failed
+ uint8_t failed; ///< Last update failed
+ uint8_t savepend; ///< Pending save
time_t accessed; ///< Last time the file was accessed
time_t updated; ///< Last time the file was checked
uint8_t sha1[20]; ///< Contents hash
static RB_HEAD(,imagecache_image) imagecache_by_url;
SKEL_DECLARE(imagecache_skel, imagecache_image_t);
-#if ENABLE_IMAGECACHE
struct imagecache_config imagecache_conf = {
.idnode.in_class = &imagecache_class,
};
static tvh_cond_t imagecache_cond;
static TAILQ_HEAD(, imagecache_image) imagecache_queue;
static mtimer_t imagecache_timer;
-#endif
-#if ENABLE_IMAGECACHE
-static int
+static inline int
sha1_empty( const uint8_t *sha1 )
{
int i;
return 0;
return 1;
}
-#endif
static int
url_cmp ( imagecache_image_t *a, imagecache_image_t *b )
return (a->id - b->id);
}
-#if ENABLE_IMAGECACHE
static htsmsg_t *
imagecache_image_htsmsg ( imagecache_image_t *img )
{
static void
imagecache_image_save ( imagecache_image_t *img )
{
+ img->savepend = 1;
if (img->state != SAVE && img->state != QUEUED && img->state != FETCHING) {
img->state = SAVE;
TAILQ_INSERT_TAIL(&imagecache_queue, img, q_link);
}
}
-
static void
imagecache_new_id ( imagecache_image_t *i )
{
imagecache_image_add ( imagecache_image_t *img )
{
int oldstate = img->state;
+ if (!imagecache_conf.enabled) return;
if (strncasecmp("file://", img->url, 7)) {
img->state = QUEUED;
if (oldstate != SAVE && oldstate != QUEUED)
TAILQ_REMOVE(&imagecache_queue, img, q_link);
+retry:
if (img->state == SAVE) {
/* Do save outside global mutex */
htsmsg_t *m = imagecache_image_htsmsg(img);
img->state = IDLE;
+ img->savepend = 0;
tvh_mutex_unlock(&global_lock);
hts_settings_save(m, "imagecache/meta/%d", img->id);
htsmsg_destroy(m);
} else if (img->state == QUEUED) {
/* Fetch */
- img->state = FETCHING;
- (void)imagecache_image_fetch(img);
+ if (imagecache_conf.enabled) {
+ img->state = FETCHING;
+ (void)imagecache_image_fetch(img);
+ }
+ if (img->savepend) {
+ img->state = SAVE;
+ goto retry;
+ }
img->state = IDLE;
} else {
}
}
-#endif /* ENABLE_IMAGECACHE */
-
/*
* Initialise
*/
int id;
/* Init vars */
- imagecache_id = 0;
-#if ENABLE_IMAGECACHE
+ imagecache_id = 0;
imagecache_conf.enabled = 0;
imagecache_conf.expire = 7; // 7 days
imagecache_conf.ok_period = 24 * 7; // weekly
imagecache_conf.ignore_sslcert = 0;
idclass_register(&imagecache_class);
-#endif
/* Create threads */
-#if ENABLE_IMAGECACHE
tvh_cond_init(&imagecache_cond, 1);
TAILQ_INIT(&imagecache_queue);
-#endif
/* Load settings */
-#if ENABLE_IMAGECACHE
if ((m = hts_settings_load("imagecache/config"))) {
idnode_load(&imagecache_conf.idnode, m);
htsmsg_destroy(m);
}
-#endif
if ((m = hts_settings_load("imagecache/meta"))) {
HTSMSG_FOREACH(f, m) {
if (!(e = htsmsg_get_map_by_field(f))) continue;
}
i = RB_INSERT_SORTED(&imagecache_by_id, img, id_link, id_cmp);
assert(!i);
-#if ENABLE_IMAGECACHE
if (img->accessed == 0) {
img->accessed = gclk();
imagecache_image_save(img);
}
if (!img->updated)
imagecache_image_add(img);
-#endif
if (imagecache_id <= id)
imagecache_id = id + 1;
}
htsmsg_destroy(m);
}
-#if ENABLE_IMAGECACHE
/* Start threads */
tvh_thread_create(&imagecache_tid, NULL, imagecache_thread, NULL, "imagecache");
// the reality its not necessary and I'd prefer to avoid dumping
// 100's of timers into the global pool
mtimer_arm_rel(&imagecache_timer, imagecache_timer_cb, NULL, sec2mono(600));
-#endif
}
{
imagecache_image_t *img;
-#if ENABLE_IMAGECACHE
tvh_mutex_lock(&global_lock);
mtimer_disarm(&imagecache_timer);
tvh_mutex_unlock(&global_lock);
tvh_cond_signal(&imagecache_cond, 1);
pthread_join(imagecache_tid, NULL);
-#endif
tvh_mutex_lock(&global_lock);
while ((img = RB_FIRST(&imagecache_by_id)) != NULL) {
-#if ENABLE_IMAGECACHE
if (img->state == SAVE) {
htsmsg_t *m = imagecache_image_htsmsg(img);
hts_settings_save(m, "imagecache/meta/%d", img->id);
htsmsg_destroy(m);
}
-#endif
imagecache_destroy(img, 0);
}
tvh_mutex_unlock(&global_lock);
}
-#if ENABLE_IMAGECACHE
-
/*
* Class save
*/
}
}
-#endif /* ENABLE_IMAGECACHE */
-
/*
* Fetch a URLs ID
+ *
+ * If imagecache is not enabled, just manage the id<->local filename
+ * mapping database.
*/
int
imagecache_get_id ( const char *url )
{
int id = 0;
imagecache_image_t *i;
-#if ENABLE_IMAGECACHE
int save = 0;
time_t clk;
-#endif
lock_assert(&global_lock);
return 0;
/* Disabled */
-#if !ENABLE_IMAGECACHE
- if (strncasecmp(url, "file://", 7))
+ if (!imagecache_conf.enabled && strncasecmp(url, "file://", 7))
return 0;
-#endif
/* Skeleton */
SKEL_ALLOC(imagecache_skel);
i = imagecache_skel;
i->url = strdup(url);
SKEL_USED(imagecache_skel);
-#if ENABLE_IMAGECACHE
+ save = 1;
imagecache_new_id(i);
imagecache_image_add(i);
- save = 1;
-#endif
}
-#if ENABLE_IMAGECACHE
- if (!strncasecmp(url, "file://", 7) || imagecache_conf.enabled)
- id = i->id;
-#else
- if (!strncasecmp(url, "file://", 7))
+
+ /* Do file:// to imagecache ID mapping even if imagecache is not enabled */
+ if (imagecache_conf.enabled || !strncasecmp(url, "file://", 7))
id = i->id;
-#endif
-#if ENABLE_IMAGECACHE
clk = gclk();
if (clk != i->accessed) {
i->accessed = clk;
}
if (save)
imagecache_image_save(i);
-#endif
return id;
}
+/*
+ *
+ */
+const char *
+imagecache_get_propstr ( const char *image, char *buf, size_t buflen )
+{
+ int id = imagecache_get_id(image);
+ if (id == 0) return image;
+ snprintf(buf, buflen, "imagecache/%d", id);
+ return buf;
+}
+
/*
* Get data
*/
}
/* Remote file */
-#if ENABLE_IMAGECACHE
else if (imagecache_conf.enabled) {
int e;
int64_t mono;
if (hts_settings_buildpath(name, len, "imagecache/data/%d", i->id))
return -1;
}
-#endif
return 0;
}
extern tvh_mutex_t imagecache_mutex;
-void imagecache_init ( void );
-void imagecache_done ( void );
+void imagecache_init ( void );
+void imagecache_done ( void );
-void imagecache_clean ( void );
-void imagecache_trigger ( void );
+void imagecache_clean ( void );
+void imagecache_trigger ( void );
// Note: will return 0 if invalid (must serve original URL)
-int imagecache_get_id ( const char *url );
+int imagecache_get_id ( const char *url );
-int imagecache_filename ( int id, char *name, size_t len );
+const char *imagecache_get_propstr ( const char *image, char *buf, size_t buflen );
+
+int imagecache_filename ( int id, char *name, size_t len );
#endif /* __IMAGE_CACHE_H__ */
#if ENABLE_SATIP_SERVER
{ "satip_server", NULL },
#endif
-#if ENABLE_IMAGECACHE
- { "imagecache", (uint32_t*)&imagecache_conf.enabled },
-#endif
#if ENABLE_TIMESHIFT
{ "timeshift", (uint32_t *)×hift_conf.enabled },
#endif
tvheadend.imgcacheconf = function(panel, index) {
- if (tvheadend.capabilities.indexOf('imagecache') === -1)
- return;
-
var cleanButton = {
name: 'clean',
builder: function() {
if (urlauth == URLAUTH_TICKET)
ticket = access_ticket_create(url_remain, access);
htsbuf_append_str(hq, "#EXTINF:-1");
- if (logo) {
- if (strncmp(logo, "imagecache/", 11) == 0) {
- htsbuf_qprintf(hq, " logo=\"%s/%s", hostpath, logo);
+ if (!strempty(logo)) {
+ int id = imagecache_get_id(logo);
+ if (id) {
+ htsbuf_qprintf(hq, " logo=\"%s/imagecache/%d", hostpath, id);
switch (urlauth) {
case URLAUTH_NONE:
break;
const char *name, *logo;
idnode_list_mapping_t *ilm;
service_t *s = NULL;
- int src;
+ int id, src;
LIST_FOREACH(ilm, &ch->ch_services, ilm_in2_link) {
/* cannot handle channels with more services for SAT>IP */
return;
name = channel_get_name(ch, blank);
logo = channel_get_icon(ch);
+ id = imagecache_get_id(logo);
snprintf(buf, sizeof(buf), "/stream/channelid/%d", channel_get_id(ch));
htsbuf_append_str(hq, "#EXTINF:-1");
- if (logo) {
- if (strncmp(logo, "imagecache/", 11) == 0) {
- htsbuf_qprintf(hq, " logo=%s/%s", hostpath, logo);
- if (urlauth == URLAUTH_CODE && !strempty(access->aa_auth))
- htsbuf_qprintf(hq, "?auth=%s", access->aa_auth);
- } else {
- htsbuf_qprintf(hq, " logo=%s", logo);
- }
+ if (id) {
+ htsbuf_qprintf(hq, " logo=%s/imagecache/%d", hostpath, id);
+ if (urlauth == URLAUTH_CODE && !strempty(access->aa_auth))
+ htsbuf_qprintf(hq, "?auth=%s", access->aa_auth);
+ } else if (!strempty(logo)) {
+ htsbuf_qprintf(hq, " logo=%s", logo);
}
htsbuf_qprintf(hq, ",%s\n%s%s?profile=pass", name, hostpath, buf);
if (urlauth == URLAUTH_CODE && !strempty(access->aa_auth))
http_channel_playlist(http_connection_t *hc, int pltype, int urlauth, channel_t *channel)
{
htsbuf_queue_t *hq;
- char buf[255], chnum[32];
- char *profile, *hostpath;
+ char buf[255], hostpath[512], chnum[32];
+ char *profile;
const char *name, *blank;
const char *lang = hc->hc_access->aa_lang_ui;
char ubuf[UUID_HEX_SIZE];
return http_noaccess_code(hc);
profile = profile_validate_name(http_arg_get(&hc->hc_req_args, "profile"));
- hostpath = http_get_hostpath(hc);
+ http_get_hostpath(hc, hostpath, sizeof(hostpath));
hq = &hc->hc_reply;
}
- free(hostpath);
free(profile);
return 0;
}
http_tag_playlist(http_connection_t *hc, int pltype, int urlauth, channel_tag_t *tag)
{
htsbuf_queue_t *hq;
- char buf[255], chnum[32], ubuf[UUID_HEX_SIZE];
- char *profile, *hostpath;
+ char buf[255], hostpath[512], chnum[32], ubuf[UUID_HEX_SIZE];
+ char *profile;
const char *name, *blank, *sort, *lang;
channel_t *ch;
channel_t **chlist;
lang = hc->hc_access->aa_lang_ui;
hq = &hc->hc_reply;
profile = profile_validate_name(http_arg_get(&hc->hc_req_args, "profile"));
- hostpath = http_get_hostpath(hc);
+ http_get_hostpath(hc, hostpath, sizeof(hostpath));
sort = http_arg_get(&hc->hc_req_args, "sort");
chlist = channel_get_sorted_list_for_tag(sort, tag, &count);
}
free(chlist);
- free(hostpath);
free(profile);
return 0;
}
http_tag_list_playlist(http_connection_t *hc, int pltype, int urlauth)
{
htsbuf_queue_t *hq;
- char buf[255];
+ char buf[255], hostpath[512];
channel_tag_t *ct;
channel_tag_t **ctlist;
channel_t *ch;
int labelidx = 0;
int idx, count = 0;
int chidx, chcount = 0;
- char *profile, *hostpath;
+ char *profile;
const char *blank, *sort, *lang;
idnode_list_mapping_t *ilm;
lang = hc->hc_access->aa_lang_ui;
hq = &hc->hc_reply;
profile = profile_validate_name(http_arg_get(&hc->hc_req_args, "profile"));
- hostpath = http_get_hostpath(hc);
+ http_get_hostpath(hc, hostpath, sizeof(hostpath));
sort = http_arg_get(&hc->hc_req_args, "sort");
ctlist = channel_tag_get_sorted_list(sort, &count);
if (pltype == PLAYLIST_M3U) {
snprintf(buf, sizeof(buf), "/playlist/tagid/%d", idnode_get_short_uuid(&ct->ct_id));
http_m3u_playlist_add(hq, hostpath, buf, profile, ct->ct_name, NULL,
- channel_tag_get_icon(ct), NULL, urlauth, hc->hc_access);
+ channel_tag_get_icon(ct),
+ NULL, urlauth, hc->hc_access);
} else if (pltype == PLAYLIST_E2) {
htsbuf_qprintf(hq, "#SERVICE 1:64:%d:0:0:0:0:0:0:0::%s\n", labelidx++, ct->ct_name);
htsbuf_qprintf(hq, "#DESCRIPTION %s\n", ct->ct_name);
free(ctlist);
free(chlist);
- free(hostpath);
free(profile);
return 0;
}
http_channel_list_playlist(http_connection_t *hc, int pltype, int urlauth)
{
htsbuf_queue_t *hq;
- char buf[255], chnum[32], ubuf[UUID_HEX_SIZE];
+ char buf[255], hostpath[512], chnum[32], ubuf[UUID_HEX_SIZE];
channel_t *ch;
channel_t **chlist;
int idx = 0, count = 0;
- char *profile, *hostpath;
+ char *profile;
const char *name, *blank, *sort, *lang;
if (access_verify2(hc->hc_access, ACCESS_STREAMING))
lang = hc->hc_access->aa_lang_ui;
profile = profile_validate_name(http_arg_get(&hc->hc_req_args, "profile"));
- hostpath = http_get_hostpath(hc);
+ http_get_hostpath(hc, hostpath, sizeof(hostpath));
sort = http_arg_get(&hc->hc_req_args, "sort");
chlist = channel_get_sorted_list(sort, 0, &count);
blank = tvh_gettext_lang(lang, channel_blank_name);
}
free(chlist);
- free(hostpath);
free(profile);
return 0;
}
http_dvr_list_playlist(http_connection_t *hc, int pltype, int urlauth)
{
htsbuf_queue_t *hq;
- char buf[255], ubuf[UUID_HEX_SIZE];
+ char buf[255], hostpath[512], ubuf[UUID_HEX_SIZE];
dvr_entry_t *de;
const char *uuid;
- char *hostpath;
off_t fsize;
time_t durration;
struct tm tm;
return HTTP_STATUS_BAD_REQUEST;
hq = &hc->hc_reply;
- hostpath = http_get_hostpath(hc);
+ http_get_hostpath(hc, hostpath, sizeof(hostpath));
htsbuf_append_str(hq, "#EXTM3U\n");
LIST_FOREACH(de, &dvrentries, de_global_link) {
htsbuf_append_str(hq, "\n");
}
- free(hostpath);
return 0;
}
http_dvr_playlist(http_connection_t *hc, int pltype, int urlauth, dvr_entry_t *de)
{
htsbuf_queue_t *hq = &hc->hc_reply;
- char buf[255], ubuf[UUID_HEX_SIZE];
+ char buf[255], hostpath[512], ubuf[UUID_HEX_SIZE];
const char *ticket_id = NULL, *uuid;
time_t durration = 0;
off_t fsize = 0;
int bandwidth = 0, ret = 0;
struct tm tm;
- char *hostpath;
if(pltype != PLAYLIST_M3U)
return HTTP_STATUS_BAD_REQUEST;
if(dvr_entry_verify(de, hc->hc_access, 1))
return HTTP_STATUS_NOT_FOUND;
- hostpath = http_get_hostpath(hc);
- durration = dvr_entry_get_stop_time(de) - dvr_entry_get_start_time(de, 0);
+ http_get_hostpath(hc, hostpath, sizeof(hostpath));
+ durration = dvr_entry_get_stop_time(de) - dvr_entry_get_start_time(de, 0);
fsize = dvr_get_filesize(de, 0);
if(fsize) {
ret = HTTP_STATUS_NOT_FOUND;
}
- free(hostpath);
return ret;
}
page_xspf(http_connection_t *hc, const char *remain, void *opaque, int urlauth)
{
htsbuf_queue_t *hq = &hc->hc_reply;
- char buf[80], *hostpath;
+ char buf[80], hostpath[512];
const char *title, *profile, *ticket, *image, *delim = "?";
if ((title = http_arg_get(&hc->hc_req_args, "title")) == NULL)
title = "TVHeadend Stream";
- hostpath = http_get_hostpath(hc);
+ http_get_hostpath(hc, hostpath, sizeof(hostpath));
htsbuf_qprintf(hq, "\
<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n\
<playlist version=\"1\" xmlns=\"http://xspf.org/ns/0/\">\r\n\
<track>\r\n\
<title>%s</title>\r\n\
<location>%s/%s", title, hostpath, remain);
- free(hostpath);
profile = http_arg_get(&hc->hc_req_args, "profile");
if (profile) {
htsbuf_qprintf(hq, "?profile=%s", profile);
page_m3u(http_connection_t *hc, const char *remain, void *opaque, int urlauth)
{
htsbuf_queue_t *hq = &hc->hc_reply;
- char buf[80], *hostpath;
+ char buf[80], hostpath[512];
const char *title, *profile, *ticket, *delim = "?";
if ((title = http_arg_get(&hc->hc_req_args, "title")) == NULL)
title = "TVHeadend Stream";
- hostpath = http_get_hostpath(hc);
+ http_get_hostpath(hc, hostpath, sizeof(hostpath));
htsbuf_qprintf(hq, "\
#EXTM3U\r\n\
#EXTINF:-1,%s\r\n\
%s/%s", title, hostpath, remain);
- free(hostpath);
profile = http_arg_get(&hc->hc_req_args, "profile");
if (profile) {
htsbuf_qprintf(hq, "?profile=%s", profile);
#include "channels.h"
#include "http.h"
#include "string_list.h"
+#include "imagecache.h"
/*
*
htsbuf_append_and_escape_xml(hq, channel_get_name(ch, ""));
htsbuf_append_str(hq, "</display-name>\n");
if (icon) {
- if (strncmp(icon, "imagecache/", 11) == 0)
- htsbuf_qprintf(hq, " <icon src=\"%s/", hostpath);
- else
+ int id = imagecache_get_id(icon);
+ if (id) {
+ htsbuf_qprintf(hq, " <icon src=\"%s/imagecache/%d\"/>\n", hostpath, id);
+ } else {
htsbuf_append_str(hq, " <icon src=\"");
- htsbuf_append_and_escape_xml(hq, icon);
- htsbuf_append_str(hq, "\"/>\n");
+ htsbuf_append_and_escape_xml(hq, icon);
+ htsbuf_append_str(hq, "\"/>\n");
+ }
}
htsbuf_append_str(hq, "</channel>\n");
}
static int
http_xmltv_channel(http_connection_t *hc, channel_t *channel)
{
- char *hostpath;
+ char hostpath[512];
if (http_access_verify_channel(hc, ACCESS_STREAMING, channel))
return http_noaccess_code(hc);
- hostpath = http_get_hostpath(hc);
+ http_get_hostpath(hc, hostpath, sizeof(hostpath));
http_xmltv_begin(&hc->hc_reply);
http_xmltv_channel_add(&hc->hc_reply, hostpath, channel);
http_xmltv_programme_add(&hc->hc_reply, hostpath, channel);
http_xmltv_end(&hc->hc_reply);
- free(hostpath);
return 0;
}
http_xmltv_tag(http_connection_t *hc, channel_tag_t *tag)
{
idnode_list_mapping_t *ilm;
- char *hostpath;
+ char hostpath[512];
channel_t *ch;
if (access_verify2(hc->hc_access, ACCESS_STREAMING))
return http_noaccess_code(hc);
- hostpath = http_get_hostpath(hc);
+ http_get_hostpath(hc, hostpath, sizeof(hostpath));
http_xmltv_begin(&hc->hc_reply);
LIST_FOREACH(ilm, &tag->ct_ctms, ilm_in1_link) {
}
http_xmltv_end(&hc->hc_reply);
- free(hostpath);
return 0;
}
http_xmltv_channel_list(http_connection_t *hc)
{
channel_t *ch;
- char *hostpath;
+ char hostpath[512];
if (access_verify2(hc->hc_access, ACCESS_STREAMING))
return http_noaccess_code(hc);
- hostpath = http_get_hostpath(hc);
+ http_get_hostpath(hc, hostpath, sizeof(hostpath));
http_xmltv_begin(&hc->hc_reply);
CHANNEL_FOREACH(ch) {
}
http_xmltv_end(&hc->hc_reply);
- free(hostpath);
return 0;
}