tvheadend/src/epggrab.c

289 lines
6.9 KiB
C

#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "htsmsg.h"
#include "settings.h"
#include "tvheadend.h"
#include "epggrab.h"
#include "epggrab/pyepg.h"
/* Thread protection */
int epggrab_confver;
pthread_mutex_t epggrab_mutex;
pthread_cond_t epggrab_cond;
/* Config */
uint32_t epggrab_advanced;
uint32_t epggrab_eit;
uint32_t epggrab_interval;
epggrab_module_t* epggrab_module;
epggrab_sched_list_t epggrab_schedule;
/* Modules */
epggrab_module_t* epggrab_module_pyepg;
/* Internal prototypes */
static void* _epggrab_thread ( void* );
static time_t _epggrab_thread_simple ( void );
static time_t _epggrab_thread_advanced ( void );
static void _epggrab_load ( void );
static void _epggrab_save ( void );
static void _epggrab_set_schedule ( int, epggrab_sched_t* );
/*
* Initialise
*/
void epggrab_init ( void )
{
/* Defaults */
epggrab_advanced = 0;
epggrab_eit = 1; // on air grab enabled
epggrab_interval = 12; // hours
epggrab_module = NULL; // disabled
/* Initialise modules */
epggrab_module_pyepg = pyepg_init();
/* Start thread */
pthread_t tid;
pthread_attr_t tattr;
pthread_attr_init(&tattr);
pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
pthread_create(&tid, &tattr, _epggrab_thread, NULL);
}
/*
* Simple run
*/
time_t _epggrab_thread_simple ( void )
{
htsmsg_t *data;
/* Copy config */
time_t ret = time(NULL) + epggrab_interval;
epggrab_module_t* mod = epggrab_module;
/* Unlock */
pthread_mutex_unlock(&epggrab_mutex);
/* Run the module */
if ( mod ) {
data = mod->grab(NULL);
if ( data ) {
pthread_mutex_lock(&global_lock);
mod->parse(data);
pthread_mutex_unlock(&global_lock);
htsmsg_destroy(data);
}
}
/* Re-lock */
pthread_mutex_lock(&epggrab_mutex);
return ret;
}
/*
* Advanced run
*
* TODO: might be nice to put each module run in another thread, in case
* they're scheduled at the same time?
*/
time_t _epggrab_thread_advanced ( void )
{
htsmsg_t *data;
epggrab_sched_t *s;
/* Determine which to run */
LIST_FOREACH(s, &epggrab_schedule, es_link) {
if ( cron_is_time(&s->cron) ) {
if ( s->mod ) {
data = s->mod->grab(s->opts);
if ( data ) {
pthread_mutex_lock(&global_lock);
s->mod->parse(data);
pthread_mutex_unlock(&global_lock);
htsmsg_destroy(data);
}
}
}
}
// TODO: make this driven off next time
// get cron to tell us when next call will run
return time(NULL) + 60;
}
/*
* Thread
*/
void* _epggrab_thread ( void* p )
{
int confver = 0;
struct timespec ts;
pthread_mutex_lock(&epggrab_mutex);
/* Load */
_epggrab_load();
/* Setup timeout */
ts.tv_nsec = 0;
ts.tv_sec = 0;
while ( 1 ) {
/* Check for config change */
while ( confver == epggrab_confver ) {
if ( pthread_cond_timedwait(&epggrab_cond, &epggrab_mutex, &ts) == ETIMEDOUT ) break;
}
/* Run grabber */
ts.tv_sec = epggrab_advanced
? _epggrab_thread_advanced()
: _epggrab_thread_simple();
}
return NULL;
}
/* **************************************************************************
* Module access
* *************************************************************************/
epggrab_module_t* epggrab_module_find_by_name ( const char *name )
{
if ( strcmp(name, "pyepg") == 0 ) return epggrab_module_pyepg;
return NULL;
}
/* **************************************************************************
* Configuration handling
* *************************************************************************/
void _epggrab_load ( void )
{
htsmsg_t *m, *s, *e, *c;
htsmsg_field_t *f;
const char *str;
epggrab_sched_t *es;
/* No config */
if ((m = hts_settings_load("epggrab/config")) == NULL)
return;
/* Load settings */
htsmsg_get_u32(m, "advanced", &epggrab_advanced);
htsmsg_get_u32(m, "eit", &epggrab_eit);
if ( !epggrab_advanced ) {
htsmsg_get_u32(m, "interval", &epggrab_interval);
str = htsmsg_get_str(m, "module");
if (str) epggrab_module = epggrab_module_find_by_name(str);
} else {
if ((s = htsmsg_get_list(m, "schedule")) != NULL) {
HTSMSG_FOREACH(f, s) {
if ((e = htsmsg_get_map_by_field(f)) != NULL) {
es = calloc(1, sizeof(epggrab_sched_t));
str = htsmsg_get_str(e, "mod");
if (str) es->mod = epggrab_module_find_by_name(str);
str = htsmsg_get_str(e, "opts");
if (str) es->opts = strdup(str);
c = htsmsg_get_map(e, "cron");
if (f) cron_unpack(&es->cron, c);
LIST_INSERT_HEAD(&epggrab_schedule, es, es_link);
}
}
}
}
}
void _epggrab_save ( void )
{
htsmsg_t *m, *s, *e, *c;
epggrab_sched_t *es;
/* Enable EIT */
/* Register */
epggrab_confver++;
pthread_cond_signal(&epggrab_cond);
/* Save */
m = htsmsg_create_map();
htsmsg_add_u32(m, "advanced", epggrab_advanced);
htsmsg_add_u32(m, "eit", epggrab_eit);
if ( !epggrab_advanced ) {
htsmsg_add_u32(m, "interval", epggrab_interval);
if ( epggrab_module )
htsmsg_add_str(m, "module", epggrab_module->name());
} else {
s = htsmsg_create_list();
LIST_FOREACH(es, &epggrab_schedule, es_link) {
e = htsmsg_create_map();
if ( es->mod ) htsmsg_add_str(e, "mod", es->mod->name());
if ( es->opts ) htsmsg_add_str(e, "opts", es->opts);
c = htsmsg_create_map();
cron_pack(&es->cron, c);
htsmsg_add_msg(e, "cron", c);
htsmsg_add_msg(s, NULL, e);
}
htsmsg_add_msg(m, "schedule", s);
}
hts_settings_save(m, "epggrab/config");
htsmsg_destroy(m);
}
void _epggrab_set_schedule ( int count, epggrab_sched_t *sched )
{
int i;
epggrab_sched_t *es;
/* Remove existing */
while ( !LIST_EMPTY(&epggrab_schedule) ) {
es = LIST_FIRST(&epggrab_schedule);
LIST_REMOVE(es, es_link);
if ( es->opts ) free(es->opts);
free(es);
}
/* Create new */
for ( i = 0; i < count; i++ ) {
es = calloc(1, sizeof(epggrab_sched_t));
es->mod = sched[i].mod;
es->cron = sched[i].cron;
if ( sched[i].opts ) es->opts = strdup(sched[i].opts);
LIST_INSERT_HEAD(&epggrab_schedule, es, es_link);
}
}
void epggrab_set_simple ( uint32_t interval, epggrab_module_t *mod )
{
/* Set config */
lock_assert(&epggrab_mutex);
epggrab_advanced = 0;
epggrab_interval = interval;
epggrab_module = mod;
/* Save */
_epggrab_save();
}
void epggrab_set_advanced ( uint32_t count, epggrab_sched_t *sched )
{
/* Set config */
lock_assert(&epggrab_mutex);
epggrab_advanced = 1;
_epggrab_set_schedule(count, sched);
/* Save */
_epggrab_save();
}
void epggrab_set_eit ( uint32_t eit )
{
/* Set config */
lock_assert(&epggrab_mutex);
epggrab_eit = eit;
/* Save */
_epggrab_save();
}