int id; ///< Internal ID
const char *url; ///< Upstream URL
int failed; ///< Last update failed
+ time_t accessed; ///< Last time the file was accessed
time_t updated; ///< Last time the file was checked
uint8_t sha1[20]; ///< Contents hash
enum {
.idnode.in_class = &imagecache_class,
};
-static htsmsg_t *imagecache_save(idnode_t *self, char *filename, size_t fsize);
+static htsmsg_t *imagecache_class_save(idnode_t *self, char *filename, size_t fsize);
+static void imagecache_destroy(imagecache_image_t *img, int delconf);
CLASS_DOC(imagecache)
.ic_event = "imagecache",
.ic_perm_def = ACCESS_ADMIN,
.ic_doc = tvh_doc_imagecache_class,
- .ic_save = imagecache_save,
+ .ic_save = imagecache_class_save,
.ic_properties = (const property_t[]){
{
.type = PT_BOOL,
"self-certified, etc.) certificates"),
.off = offsetof(struct imagecache_config, ignore_sslcert),
},
+ {
+ .type = PT_U32,
+ .id = "",
+ .name = N_("Expire time"),
+ .desc = N_("The time in hours after the cached URL will "
+ "be removed. The time starts when the URL was "
+ "lastly requested. Zero means unlimited cache "
+ "(not recommended)."),
+ .off = offsetof(struct imagecache_config, expire),
+ },
{
.type = PT_U32,
.id = "ok_period",
char hex[41];
htsmsg_t *m = htsmsg_create_map();
htsmsg_add_str(m, "url", img->url);
+ if (img->accessed)
+ htsmsg_add_s64(m, "accessed", img->accessed);
if (img->updated)
htsmsg_add_s64(m, "updated", img->updated);
if (!sha1_empty(img->sha1)) {
if (img->url == NULL || img->url[0] == '\0')
return res;
- urlinit(&url);
-
/* Open file */
if (hts_settings_buildpath(path, sizeof(path), "imagecache/data/%d",
img->id))
/* Fetch (release lock, incase of delays) */
pthread_mutex_unlock(&global_lock);
+ urlinit(&url);
+
/* Build command */
tvhdebug(LS_IMAGECACHE, "fetch %s", img->url);
memset(&url, 0, sizeof(url));
static void
imagecache_timer_cb ( void *p )
{
- time_t now, when;
- imagecache_image_t *img;
- time(&now);
- RB_FOREACH(img, &imagecache_by_url, url_link) {
+ time_t now = gclk(), when;
+ imagecache_image_t *img, *img_next;
+ for (img = RB_FIRST(&imagecache_by_url); img; img = img_next) {
+ img_next = RB_NEXT(img, url_link);
+ if (imagecache_conf.expire > 0 && img->accessed > 0) {
+ when = img->accessed + imagecache_conf.expire * 24 * 3600;
+ if (when < now) {
+ tvhdebug(LS_IMAGECACHE, "expired: %s", img->url);
+ imagecache_destroy(img, 1);
+ }
+ }
if (img->state != IDLE) continue;
when = img->failed ? imagecache_conf.fail_period
: imagecache_conf.ok_period;
imagecache_id = 0;
#if ENABLE_IMAGECACHE
imagecache_conf.enabled = 0;
+ imagecache_conf.expire = 7; // 7 days
imagecache_conf.ok_period = 24 * 7; // weekly
imagecache_conf.fail_period = 24; // daily
imagecache_conf.ignore_sslcert = 0;
#if ENABLE_IMAGECACHE
/*
- * Save
+ * Class save
*/
static htsmsg_t *
-imagecache_save ( idnode_t *self, char *filename, size_t fsize )
+imagecache_class_save ( idnode_t *self, char *filename, size_t fsize )
{
htsmsg_t *c = htsmsg_create_map();
idnode_save(&imagecache_conf.idnode, c);
int
imagecache_get_id ( const char *url )
{
- int id = 0;
+ int id = 0, save = 0;
+ time_t clk;
imagecache_image_t *i;
lock_assert(&global_lock);
imagecache_new_id(i);
imagecache_image_add(i);
#endif
- imagecache_image_save(i);
+ save = 1;
}
#if ENABLE_IMAGECACHE
if (!strncasecmp(url, "file://", 7) || imagecache_conf.enabled)
if (!strncasecmp(url, "file://", 7))
id = i->id;
#endif
-
+
+ clk = gclk();
+ if (clk != i->accessed) {
+ i->accessed = clk;
+ save = 1;
+ }
+ if (save && i->state != IDLE)
+ imagecache_image_save(i);
return id;
}