]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
Complete re-write of the epggrab infastructure, trying to generalise stuff a bit...
authorAdam Sutton <dev@adamsutton.me.uk>
Fri, 1 Jun 2012 21:17:47 +0000 (22:17 +0100)
committerAdam Sutton <dev@adamsutton.me.uk>
Mon, 30 Jul 2012 14:47:21 +0000 (15:47 +0100)
src/cron.c
src/cron.h
src/epggrab.c
src/epggrab.h
src/epggrab/eit.c
src/epggrab/eit.h
src/epggrab/pyepg.c
src/epggrab/pyepg.h
src/epggrab/xmltv.c
src/epggrab/xmltv.h

index efdd8c3269e2a1b88f41fb1be0a8b3938cbfe4f2..6d7a9887d5635f27bdaae4cc36de72ece83d972f 100644 (file)
@@ -91,9 +91,11 @@ static int _cron_parse ( cron_t *cron, const char *str )
   return 1; // TODO: do proper validation
 }
 
-cron_t *cron_create ( void )
+cron_t *cron_create ( const char *str )
 {
-  return calloc(1, sizeof(cron_t));
+  cron_t *c = calloc(1, sizeof(cron_t));
+  if (str) cron_set_string(c, str);
+  return c;
 }
 
 void cron_destroy ( cron_t *cron )
@@ -160,11 +162,7 @@ void cron_serialize ( cron_t *cron, htsmsg_t *msg )
 
 cron_t *cron_deserialize ( htsmsg_t *msg )
 {
-  // TODO: validate the string!
-  cron_t *cron = cron_create();
-  const char *str = htsmsg_get_str(msg, "cron");
-  if (str) cron_set_string(cron, str);
-  return cron;
+  return cron_create(htsmsg_get_str(msg, "cron"));
 }
 
 #if 0
index f4d749ccb3ec630721865da2fe7f3fc026c6a49e..6c42b11d7847c841880e403b554c871115005c79 100644 (file)
@@ -13,7 +13,7 @@
 
 typedef struct cron cron_t;
 
-cron_t     *cron_create        ( void );
+cron_t     *cron_create        ( const char *str );
 void        cron_destroy       ( cron_t *cron );
 const char *cron_get_string    ( cron_t *cron );
 int         cron_set_string    ( cron_t *cron, const char *str );
index b1107b0c17cca22e1b8b6315eecbaceb410029f2..c8a5da95cb50cf5c069af3898df598f5a2b021f3 100644 (file)
 #include "channels.h"
 
 /* Thread protection */
-int                  epggrab_confver;
-pthread_mutex_t      epggrab_mutex;
-pthread_cond_t       epggrab_cond;
+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 */
-LIST_HEAD(epggrab_module_list, epggrab_module);
-struct epggrab_module_list epggrab_modules;
-
-/* 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* );
+uint32_t              epggrab_advanced;
+uint32_t              epggrab_eit;
+uint32_t              epggrab_interval;
+epggrab_module_t*     epggrab_module;
+epggrab_sched_list_t  epggrab_schedule;
+epggrab_module_list_t epggrab_modules;
 
-/*
- * Initialise
- */
-void epggrab_init ( void )
+/* **************************************************************************
+ * Modules
+ * *************************************************************************/
+
+static int _ch_id_cmp ( void *a, void *b )
+{
+  return strcmp(((epggrab_channel_t*)a)->id,
+                ((epggrab_channel_t*)b)->id);
+}
+
+static int _ch_match ( epggrab_channel_t *ec, channel_t *ch )
+{
+  return 0;
+}
+
+void epggrab_module_channels_load ( epggrab_module_t *mod )
+{
+  char path[100];
+  uint32_t chid;
+  htsmsg_t *m;
+  htsmsg_field_t *f;
+  epggrab_channel_t *ec;
+  channel_t *ch;
+
+  sprintf(path, "epggrab/%s/channels", mod->id);
+  if ((m = hts_settings_load(path))) {
+    HTSMSG_FOREACH(f, m) {
+      if ( !htsmsg_get_u32(m, f->hmf_name, &chid) ) {
+        ch = channel_find_by_identifier(chid);
+        if (ch) {
+          ec = calloc(1, sizeof(epggrab_channel_t));
+          ec->id      = strdup(f->hmf_name);
+          ec->channel = ch;
+          RB_INSERT_SORTED(mod->channels, ec, link, _ch_id_cmp);
+        }
+      }
+    }
+  }
+}
+
+void epggrab_module_channels_save ( epggrab_module_t *mod )
+{
+  char path[100];
+  epggrab_channel_t *c;
+  htsmsg_t *m = htsmsg_create_map();
+
+  sprintf(path, "epggrab/%s/channels", mod->id);
+  RB_FOREACH(c, mod->channels, link) {
+    if (c->channel) htsmsg_add_u32(m, c->id, c->channel->ch_id);
+  }
+  hts_settings_save(m, path);
+}
+
+int epggrab_module_channel_add ( epggrab_module_t *mod, channel_t *ch )
+{
+  int save = 0;
+  epggrab_channel_t *egc;
+  RB_FOREACH(egc, mod->channels, link) {
+    if (_ch_match(egc, ch) ) {
+      save = 1;
+      egc->channel = ch;
+      break;
+    }
+  }
+  return save;
+}
+
+int epggrab_module_channel_rem ( epggrab_module_t *mod, channel_t *ch )
+{
+  int save = 0;
+  epggrab_channel_t *egc;
+  RB_FOREACH(egc, mod->channels, link) {
+    if (egc->channel == ch) {
+      save = 1;
+      egc->channel = NULL;
+      break;
+    }
+  }
+  return save;
+}
+
+int epggrab_module_channel_mod ( epggrab_module_t *mod, channel_t *ch )
+{
+  return epggrab_module_channel_add(mod, ch);
+}
+
+
+epggrab_channel_t *epggrab_module_channel_create ( epggrab_module_t *mod )
+{
+  return NULL;
+}
+
+epggrab_channel_t *epggrab_module_channel_find
+  ( epggrab_module_t *mod, const char *id )
+{
+  epggrab_channel_t skel; 
+  skel.id = (char*)id;
+  return RB_FIND(mod->channels, &skel, link, _ch_id_cmp);
+}
+
+epggrab_module_t* epggrab_module_find_by_id ( const char *id )
 {
   epggrab_module_t *m;
+  LIST_FOREACH(m, &epggrab_modules, link) {
+    if ( !strcmp(m->id, id) ) return m;
+  }
+  return NULL;
+}
 
-  /* Defaults */
-  epggrab_advanced  = 0;
-  epggrab_eit       = 1;         // on air grab enabled
-  epggrab_interval  = 12 * 3600; // hours
-  epggrab_module    = NULL;      // disabled
+htsmsg_t *epggrab_module_list ( void )
+{
+  htsmsg_t *a = htsmsg_create_list();
+  return a;
+}
 
-  /* Initialise modules */
-  m = eit_init();
-  LIST_INSERT_HEAD(&epggrab_modules, m, glink);
-#if TODO_XMLTV_SUPPORT
-  m = xmltv_init();
-  LIST_INSERT_HEAD(&epggrab_modules, m, glink);
-#endif
-  m = pyepg_init();
-  LIST_INSERT_HEAD(&epggrab_modules, m, glink);
+/* **************************************************************************
+ * Configuration
+ * *************************************************************************/
 
-  /* 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);
+static int _update_str ( char **dst, const char *src )
+{
+  int save = 0;
+  if ( !(*dst) && src ) {
+    *dst = strdup(src);
+    save = 1;
+  } else if ( (*dst) && !src ) {
+    free(*dst);
+    *dst = NULL;
+    save = 1;
+  } else if ( strcmp(*dst, src) ) {
+    free(*dst);
+    *dst = strdup(src);
+    save = 1;
+  }
+  return save;
+} 
+
+static int _epggrab_schedule_deserialize ( htsmsg_t *m )
+{ 
+  int save = 0;
+  htsmsg_t *a, *e;
+  htsmsg_field_t *f;
+  epggrab_sched_t *es;
+  epggrab_module_t *mod;
+  const char *str;
+
+  es = LIST_FIRST(&epggrab_schedule);
+  if ( (a = htsmsg_get_list(m, "schedule")) ) {
+    HTSMSG_FOREACH(f, a) {
+      if ((e = htsmsg_get_map_by_field(f))) {
+        if (es) {
+          es = LIST_NEXT(es, link);
+        } else {
+          es   = calloc(1, sizeof(epggrab_sched_t));
+          save = 1;
+          LIST_INSERT_HEAD(&epggrab_schedule, es, link);
+        }
+
+        mod = NULL;
+        if ((str = htsmsg_get_str(e, "module")))
+          mod = epggrab_module_find_by_id(str);
+        if (es->mod != mod) {
+          es->mod = mod;
+          save    = 1;
+        }
+
+        save |= _update_str(&es->cmd,  htsmsg_get_str(e, "command"));
+        save |= _update_str(&es->opts, htsmsg_get_str(e, "options"));
+        str   = htsmsg_get_str(e, "cron");
+        if (es->cron) {
+          if (!str) {
+            free(es->cron);
+            es->cron = NULL;
+            save     = 1;
+          } else {
+            save |= cron_set_string(es->cron, str);
+          }
+        } else if (str) {
+          es->cron = cron_create(str);
+          save     = 1;
+        }
+      }
+    }
+  }
+  
+  if (es)
+    while ( LIST_NEXT(es, link) ) {
+      LIST_REMOVE(es, link);
+      save = 1;
+    }
+
+  return save;
+}
+
+static htsmsg_t *_epggrab_schedule_serialize ( void )
+{
+  epggrab_sched_t *es;
+  htsmsg_t *e, *a;
+  a = htsmsg_create_list();
+  LIST_FOREACH(es, &epggrab_schedule, link) {
+    e = htsmsg_create_map();
+    if ( es->mod  ) htsmsg_add_str(e, "module",  es->mod->id);
+    if ( es->cmd  ) htsmsg_add_str(e, "command", es->cmd);
+    if ( es->opts ) htsmsg_add_str(e, "options", es->opts);
+    if ( es->cron ) cron_serialize(es->cron, e);
+    htsmsg_add_msg(a, NULL, e);
+  }
+  return a;
+}
+
+static void _epggrab_load ( void )
+{
+  htsmsg_t *m, *a;
+  const char *str;
+  
+  /* 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);
+  htsmsg_get_u32(m, "interval", &epggrab_interval);
+  if ( (str = htsmsg_get_str(m, "module")) )
+    epggrab_module = epggrab_module_find_by_id(str);
+  if ( (a = htsmsg_get_list(m, "schedule")) )
+    _epggrab_schedule_deserialize(a);
+  htsmsg_destroy(m);
+}
+
+void epggrab_save ( void )
+{
+  htsmsg_t *m;
+
+  /* Register */
+  epggrab_confver++;
+  pthread_cond_signal(&epggrab_cond);
+
+  /* Save */
+  m = htsmsg_create_map();
+  htsmsg_add_u32(m, "advanced",   epggrab_advanced);
+  htsmsg_add_u32(m, "eitenabled", epggrab_eitenabled);
+  htsmsg_add_u32(m, "interval",   epggrab_interval);
+  if ( epggrab_module )
+    htsmsg_add_str(m, "module", epggrab_module->id);
+  htsmsg_add_msg(m, "schedule", _epggrab_schedule_serialize());
+  hts_settings_save(m, "epggrab/config");
+  htsmsg_destroy(m);
+}
+
+int epggrab_set_advanced ( uint32_t advanced )
+{ 
+  int save = 0;
+  if ( epggrab_advanced != advanced ) {
+    save = 1;
+    epggrab_advanced = advanced;
+  }
+  return save;
+}
+
+int epggrab_set_eitenabled ( uint32_t eitenabled )
+{
+  int save = 0;
+  if ( epggrab_eit != eitenabled ) {
+    save = 1;
+    eitenabled = eitenabled;
+  }
+  return save;
+}
+
+int epggrab_set_interval ( uint32_t interval )
+{
+  int save = 0;
+  if ( epggrab_interval != interval ) {
+    save = 1;
+    epggrab_interval = interval;
+  }
+  return save;
+}
+
+int epggrab_set_module ( epggrab_module_t *mod )
+{
+  int save = 0;
+  if ( mod && epggrab_module != mod ) {
+    save = 1;
+    epggrab_module = mod;
+  }
+  return save;
+}
+
+int epggrab_set_module_by_id ( const char *id )
+{
+  return epggrab_set_module(epggrab_module_find_by_id(id));
 }
 
+int epggrab_set_schedule ( htsmsg_t *sched )
+{
+  return _epggrab_schedule_deserialize(sched);
+}
+
+htsmsg_t *epggrab_get_schedule ( void )
+{
+  return _epggrab_schedule_serialize();
+}
+
+/* **************************************************************************
+ * Module Execution
+ * *************************************************************************/
+
 /*
  * Grab from module
  */
-static void _epggrab_module_run ( epggrab_module_t *mod, const char *opts )
+static void _epggrab_module_run 
+  ( epggrab_module_t *mod, const char *icmd, const char *iopts )
 {
   int save = 0;
   time_t tm1, tm2;
   htsmsg_t *data;
   epggrab_stats_t stats;
-  memset(&stats, 0, sizeof(stats));
+  char *cmd = NULL, *opts = NULL;
 
   /* Check */
-  if ( !mod ) return;
+  if ( !mod || !mod->grab || !mod->parse ) return;
+  
+  /* Dup before unlock */
+  if ( !icmd  ) cmd  = strdup(icmd);
+  if ( !iopts ) opts = strdup(iopts);
+  pthread_mutex_unlock(&epggrab_mutex);
   
   /* Grab */
   time(&tm1);
-  data = mod->grab(opts);
+  data = mod->grab(mod, cmd, opts);
   time(&tm2);
 
   /* Process */
   if ( data ) {
-    tvhlog(LOG_DEBUG, mod->name(), "grab took %d seconds", tm2 - tm1);
+
+    /* Parse */
+    memset(&stats, 0, sizeof(stats));
+    tvhlog(LOG_DEBUG, mod->id, "grab took %d seconds", tm2 - tm1);
     pthread_mutex_lock(&global_lock);
     time(&tm1);
-    save |= mod->parse(data, &stats);
+    save |= mod->parse(mod, data, &stats);
     time(&tm2);
     if (save) epg_updated();  
     pthread_mutex_unlock(&global_lock);
     htsmsg_destroy(data);
 
     /* Debug stats */
-    tvhlog(LOG_DEBUG, mod->name(), "parse took %d seconds", tm2 - tm1);
-    tvhlog(LOG_DEBUG, mod->name(), "  channels   tot=%5d new=%5d mod=%5d",
+    tvhlog(LOG_DEBUG, mod->id, "parse took %d seconds", tm2 - tm1);
+    tvhlog(LOG_DEBUG, mod->id, "  channels   tot=%5d new=%5d mod=%5d",
            stats.channels.total, stats.channels.created,
            stats.channels.modified);
-    tvhlog(LOG_DEBUG, mod->name(), "  brands     tot=%5d new=%5d mod=%5d",
+    tvhlog(LOG_DEBUG, mod->id, "  brands     tot=%5d new=%5d mod=%5d",
            stats.brands.total, stats.brands.created,
            stats.brands.modified);
-    tvhlog(LOG_DEBUG, mod->name(), "  seasons    tot=%5d new=%5d mod=%5d",
+    tvhlog(LOG_DEBUG, mod->id, "  seasons    tot=%5d new=%5d mod=%5d",
            stats.seasons.total, stats.seasons.created,
            stats.seasons.modified);
-    tvhlog(LOG_DEBUG, mod->name(), "  episodes   tot=%5d new=%5d mod=%5d",
+    tvhlog(LOG_DEBUG, mod->id, "  episodes   tot=%5d new=%5d mod=%5d",
            stats.episodes.total, stats.episodes.created,
            stats.episodes.modified);
-    tvhlog(LOG_DEBUG, mod->name(), "  broadcasts tot=%5d new=%5d mod=%5d",
+    tvhlog(LOG_DEBUG, mod->id, "  broadcasts tot=%5d new=%5d mod=%5d",
            stats.broadcasts.total, stats.broadcasts.created,
            stats.broadcasts.modified);
 
   } else {
-    tvhlog(LOG_WARNING, mod->name(), "grab returned no data");
+    tvhlog(LOG_WARNING, mod->id, "grab returned no data");
   }
+
+  /* Free a re-lock */
+  if (cmd)  free(cmd);
+  if (opts) free(cmd);
+  pthread_mutex_lock(&epggrab_mutex);
 }
 
 /*
  * Simple run
  */
-time_t _epggrab_thread_simple ( void )
+static time_t _epggrab_thread_simple ( void )
 {
   /* Copy config */
   time_t            ret = time(NULL) + epggrab_interval;
   epggrab_module_t* mod = epggrab_module;
 
-  /* Unlock */
-  pthread_mutex_unlock(&epggrab_mutex);
-
   /* Run the module */
-  _epggrab_module_run(mod, NULL);
-
-  /* Re-lock */
-  pthread_mutex_lock(&epggrab_mutex);
+  _epggrab_module_run(mod, NULL, NULL);
 
   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 )
+static time_t _epggrab_thread_advanced ( void )
 {
+  time_t ret;
   epggrab_sched_t *s;
 
   /* Determine which to run */
-  LIST_FOREACH(s, &epggrab_schedule, es_link) {
-    if ( cron_is_time(&s->cron) ) {
-      _epggrab_module_run(s->mod, s->opts);
+  time(&ret);
+  LIST_FOREACH(s, &epggrab_schedule, link) {
+    if ( cron_is_time(s->cron) ) {
+      _epggrab_module_run(s->mod, s->cmd, s->opts);
+      break; // TODO: can only run once else config may have changed
     }
   }
 
-  // TODO: make this driven off next time
-  //       get cron to tell us when next call will run
-  return time(NULL) + 60;
+  return ret + 60;
 }
 
 /*
  * Thread
  */
-void* _epggrab_thread ( void* p )
+static void* _epggrab_thread ( void* p )
 {
   int confver = 0;
   struct timespec ts;
@@ -184,8 +457,10 @@ void* _epggrab_thread ( void* p )
 
     /* Check for config change */
     while ( confver == epggrab_confver ) {
-      if ( pthread_cond_timedwait(&epggrab_cond, &epggrab_mutex, &ts) == ETIMEDOUT ) break;
+      int err = pthread_cond_timedwait(&epggrab_cond, &epggrab_mutex, &ts);
+      if ( err == ETIMEDOUT ) break;
     }
+    confver = epggrab_confver;
 
     /* Run grabber */
     ts.tv_sec = epggrab_advanced
@@ -197,301 +472,59 @@ void* _epggrab_thread ( void* p )
 }
 
 /* **************************************************************************
- * Module access
- * *************************************************************************/
-
-epggrab_module_t* epggrab_module_find_by_name ( const char *name )
-{
-  epggrab_module_t *m;
-  LIST_FOREACH(m, &epggrab_modules, glink) {
-    if ( !strcmp(m->name(), name) ) return m;
-  }
-  return NULL;
-}
-
-/* **************************************************************************
- * Channel handling
- *
- * TODO: this is all a bit messy (too much indirection?) but it works!
- *
- * TODO: need to save mappings to disk
- *
- * TODO: probably want rules on what can be updated etc...
+ * Global Functions
  * *************************************************************************/
 
-static int _ch_id_cmp ( void *a, void *b )
-{
-  return strcmp(((epggrab_channel_t*)a)->id,
-                ((epggrab_channel_t*)b)->id);
-}
-
-static channel_t *_channel_find ( epggrab_channel_t *ch )
+/*
+ * Initialise
+ */
+void epggrab_init ( void )
 {
-  channel_t *ret = NULL;
-  if (ch->name) ret = channel_find_by_name(ch->name, 0, 0);
-  return ret;
-}
+  /* Defaults */
+  epggrab_advanced  = 0;
+  epggrab_eit       = 1;         // on air grab enabled
+  epggrab_interval  = 12 * 3600; // hours
+  epggrab_module    = NULL;      // disabled
 
-static int _channel_match ( epggrab_channel_t *egc, channel_t *ch )
-{
-  /* Already linked */
-  if ( egc->channel ) return 0;
-  
-  /* Name match */
-  if ( !strcmp(ch->ch_name, egc->name) ) return 1;
+  /* Initialise modules */
+  eit_init(&epggrab_modules);
+  xmltv_init(&epggrab_modules);
+  pyepg_init(&epggrab_modules);
 
-  return 0;
+  /* 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);
 }
 
 void epggrab_channel_add ( channel_t *ch )
 {
   epggrab_module_t *m;
-  LIST_FOREACH(m, &epggrab_modules, glink) {
-    if (m->ch_add) m->ch_add(ch);
+  LIST_FOREACH(m, &epggrab_modules, link) {
+    if (m->ch_add) 
+      if (m->ch_add(m, ch) && m->ch_save)
+        m->ch_save(m);
   }
 }
 
 void epggrab_channel_rem ( channel_t *ch )
 {
   epggrab_module_t *m;
-  LIST_FOREACH(m, &epggrab_modules, glink) {
-    if (m->ch_rem) m->ch_rem(ch);
+  LIST_FOREACH(m, &epggrab_modules, link) {
+    if (m->ch_rem) 
+      if (m->ch_rem(m, ch) && m->ch_save)
+        m->ch_save(m);
   }
 }
 
 void epggrab_channel_mod ( channel_t *ch )
 {
   epggrab_module_t *m;
-  LIST_FOREACH(m, &epggrab_modules, glink) {
-    if (m->ch_mod) m->ch_mod(ch);
+  LIST_FOREACH(m, &epggrab_modules, link) {
+    if (m->ch_mod) 
+      if (m->ch_mod(m, ch) && m->ch_save)
+        m->ch_save(m);
   }
 }
-
-void epggrab_module_channels_load
-  ( const char *path, epggrab_channel_tree_t *tree )
-{
-  uint32_t chid;
-  htsmsg_t *m;
-  htsmsg_field_t *f;
-  epggrab_channel_t *ec;
-  channel_t *ch;
-
-  if ((m = hts_settings_load(path))) {
-    HTSMSG_FOREACH(f, m) {
-      if ( !htsmsg_get_u32(m, f->hmf_name, &chid) ) {
-        ch = channel_find_by_identifier(chid);
-        if (ch) {
-          ec = calloc(1, sizeof(epggrab_channel_t));
-          ec->id      = strdup(f->hmf_name);
-          ec->channel = ch;
-          assert(RB_INSERT_SORTED(tree, ec, glink, _ch_id_cmp) == NULL);
-        }
-      }
-    }
-  }
-}
-
-void epggrab_module_channels_save
-  ( const char *path, epggrab_channel_tree_t *tree )
-{
-  epggrab_channel_t *c;
-  htsmsg_t *m = htsmsg_create_map();
-  RB_FOREACH(c, tree, glink) {
-    if (c->channel) htsmsg_add_u32(m, c->id, c->channel->ch_id);
-  }
-  hts_settings_save(m, path);
-}
-
-epggrab_channel_t *epggrab_module_channel_create 
-  ( epggrab_channel_tree_t *tree, epggrab_channel_t *iskel, int *save )
-{
-  epggrab_channel_t *egc;
-  static epggrab_channel_t *skel = NULL;
-  if (!skel) skel = calloc(1, sizeof(epggrab_channel_t));
-  skel->id   = iskel->id;
-  skel->name = iskel->name;
-  egc = RB_INSERT_SORTED(tree, skel, glink, _ch_id_cmp);
-  if ( egc == NULL ) {
-    skel->id      = strdup(skel->id);
-    skel->name    = strdup(skel->name);
-    skel->channel = _channel_find(skel);
-    if ( skel->channel ) *save |= 1;
-    egc  = skel;
-    skel = NULL;
-  }
-  return egc;
-}
-
-epggrab_channel_t *epggrab_module_channel_find 
-  ( epggrab_channel_tree_t *tree, const char *id )
-{
-  epggrab_channel_t skel;
-  skel.id = (char*)id;
-  return RB_FIND(tree, &skel, glink, _ch_id_cmp); 
-}
-
-int epggrab_module_channel_add ( epggrab_channel_tree_t *tree, channel_t *ch )
-{
-  int save = 0;
-  epggrab_channel_t *egc;
-  RB_FOREACH(egc, tree, glink) {
-    if (_channel_match(egc, ch) ) {
-      save = 1;
-      egc->channel = ch;
-      break;
-    }
-  }
-  return save;
-}
-
-int epggrab_module_channel_rem ( epggrab_channel_tree_t *tree, channel_t *ch )
-{
-  int save = 0;
-  epggrab_channel_t *egc;
-  RB_FOREACH(egc, tree, glink) {
-    if (egc->channel == ch) {
-      save = 1;
-      egc->channel = NULL;
-      break;
-    }
-  }
-  return save;
-}
-
-int epggrab_module_channel_mod ( epggrab_channel_tree_t *tree, channel_t *ch )
-{
-  return epggrab_module_channel_add(tree, ch);
-}
-
-/* **************************************************************************
- * 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);
-        }
-      }
-    }
-  }
-  htsmsg_destroy(m);
-}
-
-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();
-}
index a06080fecb25fd5853a639de09067cd0c371eb6d..28a6b35a1342df97854ec2169d023210a8d84321 100644 (file)
@@ -3,14 +3,12 @@
 
 #include <pthread.h>
 #include "cron.h"
+#include "channels.h"
 
 /* **************************************************************************
- * Type definitions
+ * Grabber Stats
  * *************************************************************************/
 
-/*
- * Grab statistics
- */
 typedef struct epggrab_stats_part
 {
   int created;
@@ -27,85 +25,142 @@ typedef struct epggrab_stats
   epggrab_stats_part_t broadcasts;
 } epggrab_stats_t;
 
+/* **************************************************************************
+ * Grabber Channels
+ * *************************************************************************/
+
 /*
  * Grab channel
  */
 typedef struct epggrab_channel
 {
+  RB_ENTRY(epggrab_channel)  link;   ///< Global link
+
   char                      *id;      ///< Grabber's ID
   char                      *name;    ///< Channel name
   struct channel            *channel; ///< Mapped channel
   // TODO: I think we might need a list of channels!
-  RB_ENTRY(epggrab_channel)  glink;   ///< Global link
 } epggrab_channel_t;
 
+/*
+ * Channel list
+ */
 RB_HEAD(epggrab_channel_tree, epggrab_channel);
 typedef struct epggrab_channel_tree epggrab_channel_tree_t;
 
+/* **************************************************************************
+ * Grabber Modules
+ * *************************************************************************/
+
+typedef struct epggrab_module epggrab_module_t;
+
 /*
  * Grabber base class
  */
-typedef struct epggrab_module
+struct epggrab_module
 {
-  const char* (*name)    ( void );
-  void        (*enable)  ( void );
-  void        (*disable) ( void );
-  htsmsg_t*   (*grab)    ( const char *opts );
-  int         (*parse)   ( htsmsg_t *data, epggrab_stats_t *stats );
-  void        (*ch_add)  ( struct channel *ch );
-  void        (*ch_rem)  ( struct channel *ch );
-  void        (*ch_mod)  ( struct channel *ch );
-
-  LIST_ENTRY(epggrab_module) glink; ///< Global list link
-} epggrab_module_t;
+  LIST_ENTRY(epggrab_module) link;      ///< Global list link
+
+  const char                 *id;       ///< Module identifier
+  const char                 *name;     ///< Module name (for display)
+  const char                 *path;     ///< Module path (for fixed config)
+  const uint8_t              simple;    ///< Include in simple list
+  const uint8_t              async;     ///< Asynchronous (not schedulable)
+  epggrab_channel_tree_t     *channels; ///< Channel list
+
+  /* Enable/Disable for async */
+  void      (*enable) ( epggrab_module_t *m, uint8_t e );
+
+  /* Synchronous grab&parse */
+  htsmsg_t* (*grab)   ( epggrab_module_t *m,
+                        const char *c, const char *o );
+  int       (*parse)  ( epggrab_module_t *m,
+                        htsmsg_t *d, epggrab_stats_t *s );
+
+  /* Channel listings */
+  int       (*ch_add)  ( epggrab_module_t *m, channel_t *ch );
+  int       (*ch_rem)  ( epggrab_module_t *m, channel_t *ch );
+  int       (*ch_mod)  ( epggrab_module_t *m, channel_t *ch );
+
+  /* Save any settings */
+  void      (*ch_save) ( epggrab_module_t *m );
+};
 
 /*
- * Schedule specification
+ * Default channel handlers
  */
-typedef struct epggrab_sched
-{ 
-  LIST_ENTRY(epggrab_sched) es_link;
-  cron_t                    cron;  ///< Cron definition
-  epggrab_module_t          *mod;  ///< Module
-  char                      *opts; ///< Extra (advanced) options
-} epggrab_sched_t;
+void epggrab_module_channels_load ( epggrab_module_t *m );
+void epggrab_module_channels_save ( epggrab_module_t *m );
+int  epggrab_module_channel_add   ( epggrab_module_t *m, channel_t *ch );
+int  epggrab_module_channel_rem   ( epggrab_module_t *m, channel_t *ch );
+int  epggrab_module_channel_mod   ( epggrab_module_t *m, channel_t *ch );
+epggrab_channel_t *epggrab_module_channel_create
+  ( epggrab_module_t *m );
+epggrab_channel_t *epggrab_module_channel_find
+  ( epggrab_module_t *m, const char *id );
 
 /*
- * Schedule list
+ * Module list
  */
-LIST_HEAD(epggrab_sched_list, epggrab_sched);
-typedef struct epggrab_sched_list epggrab_sched_list_t;
-
-/* **************************************************************************
- * Variables
- * *************************************************************************/
+LIST_HEAD(epggrab_module_list, epggrab_module);
+typedef struct epggrab_module_list epggrab_module_list_t;
 
 /*
- * Lock this if accessing configuration
+ * Access the Module list
  */
-pthread_mutex_t epggrab_mutex;
+epggrab_module_t* epggrab_module_find_by_id ( const char *id );
+htsmsg_t*         epggrab_module_list       ( void );
 
 /* **************************************************************************
- * Functions
+ * Configuration
  * *************************************************************************/
 
 /*
- * Setup
+ * Schedule specification (for advanced config)
  */
-void epggrab_init ( void );
+typedef struct epggrab_sched
+{ 
+  LIST_ENTRY(epggrab_sched) link;
+  cron_t                    *cron;  ///< Cron definition
+  epggrab_module_t          *mod;   ///< Module
+  char                      *cmd;   ///< Command
+  char                      *opts;  ///< Extra (advanced) options
+} epggrab_sched_t;
+
+/*
+ * Schedule list
+ */
+LIST_HEAD(epggrab_sched_list, epggrab_sched);
+typedef struct epggrab_sched_list epggrab_sched_list_t;
 
 /*
- * Access the list of supported modules
+ * Configuration
  */
-//epggrab_module_t** epggrab_module_list         ( void );
-epggrab_module_t*  epggrab_module_find_by_name ( const char *name );
+extern pthread_mutex_t      epggrab_mutex;
+extern uint32_t             epggrab_advanced;
+extern uint32_t             epggrab_eitenabled;
+extern uint32_t             epggrab_interval;
+extern epggrab_module_t*    epggrab_module;
+extern epggrab_sched_list_t epggrab_schedule;
+
+htsmsg_t *epggrab_get_schedule ( void );
 
 /*
- * Set configuration
+ * Update
  */
-void epggrab_set_simple   ( uint32_t interval, epggrab_module_t* mod );
-void epggrab_set_advanced ( uint32_t count, epggrab_sched_t* sched );
-void epggrab_set_eit      ( uint32_t eit );
+int  epggrab_set_advanced     ( uint32_t advanced );
+int  epggrab_set_eitenabled   ( uint32_t eitenabled );
+int  epggrab_set_interval     ( uint32_t interval );
+int  epggrab_set_module       ( epggrab_module_t *module );
+int  epggrab_set_module_by_id ( const char *id );
+int  epggrab_set_schedule     ( htsmsg_t *sched );
+void epggrab_save             ( void );
+
+/* **************************************************************************
+ * Global Functions
+ * *************************************************************************/
+
+void epggrab_init ( void );
 
 /*
  * Channel handling
@@ -114,16 +169,4 @@ void epggrab_channel_add ( struct channel *ch );
 void epggrab_channel_rem ( struct channel *ch );
 void epggrab_channel_mod ( struct channel *ch );
 
-/*
- * Module specific channel handling
- */
-void epggrab_module_channels_load ( const char *path, epggrab_channel_tree_t *tree );
-void epggrab_module_channels_save ( const char *path, epggrab_channel_tree_t *tree );
-int epggrab_module_channel_add ( epggrab_channel_tree_t *tree, struct channel *ch );
-int epggrab_module_channel_rem ( epggrab_channel_tree_t *tree, struct channel *ch );
-int epggrab_module_channel_mod ( epggrab_channel_tree_t *tree, struct channel *ch );
-
-epggrab_channel_t *epggrab_module_channel_create ( epggrab_channel_tree_t *tree, epggrab_channel_t *ch, int *save );
-epggrab_channel_t *epggrab_module_channel_find ( epggrab_channel_tree_t *tree, const char *id );
-
 #endif /* __EPGGRAB_H__ */
index 6fea4c9d789bde2449e3962280ab178183e171da..ba5368df04014e104eb044f04ad4ad424ce471e3 100644 (file)
@@ -16,6 +16,7 @@
  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <string.h>
 #include "tvheadend.h"
 #include "channels.h"
 #include "epg.h"
  * Module Setup
  * ***********************************************************************/
 
-static epggrab_module_t eit_module;
-
-static const char* _eit_name ( void )
-{
-  return "eit";
-}
-
 static void _eit_episode_uri 
   ( char *uri, const char *title, const char *summary )
 {
@@ -90,14 +84,11 @@ void eit_callback ( channel_t *ch, int id, time_t start, time_t stop,
   }
 }
 
-epggrab_module_t* eit_init ( void )
+epggrab_module_t _eit_mod;
+void eit_init ( epggrab_module_list_t *list )
 {
-  // Note: the EIT grabber is very different to the others, in that
-  //       its asynchronous based on DVB data stream
-  eit_module.enable  = NULL;
-  eit_module.disable = NULL;
-  eit_module.grab    = NULL;
-  eit_module.parse   = NULL;
-  eit_module.name    = _eit_name;
-  return &eit_module;
+  _eit_mod.id    = strdup("eit");
+  _eit_mod.name  = strdup("EIT On-Air Grabber");
+  *((uint8_t*)&_eit_mod.async) = 1;
+  LIST_INSERT_HEAD(list, &_eit_mod, link);
 }
index 3b0870c481a0a8f971729381a0bddf7898b8e0ec..c30341e5e84df4b8acd35d42b5ba91964c630c40 100644 (file)
@@ -21,7 +21,7 @@
 
 #include "epggrab.h"
 
-epggrab_module_t *eit_init ( void );
+void eit_init ( epggrab_module_list_t *list );
 
 void eit_callback ( struct channel *ch, int id, time_t start, time_t stop,
                     const char *title, const char *desc,
index 538b4a2696da5f844d50ac5ac723b6d9dfd12ffd..2155bfde60ea169c989238e722230ab439d3cd13 100644 (file)
 #include "channels.h"
 
 epggrab_channel_tree_t _pyepg_channels;
-
-/* **************************************************************************
- * Config/Load save
- * *************************************************************************/
-
-static void _pyepg_load ( void )
-{
-  epggrab_module_channels_load("epggrab/pyepg/channels", &_pyepg_channels);
-}
-
-static void _pyepg_save ( void )
-{
-  epggrab_module_channels_save("epggrab/pyepg/channels", &_pyepg_channels);
-}
-
-/* **************************************************************************
- * Channels
- * *************************************************************************/
-
+epggrab_module_t       _pyepg_sync;
+epggrab_module_t       _pyepg_async;
 
 static channel_t *_pyepg_channel_create ( epggrab_channel_t *skel, int *save )
 {
-  epggrab_channel_t *ch
-    = epggrab_module_channel_create(&_pyepg_channels, skel, save);
-  if (ch) return ch->channel;
   return NULL;
 }
 
 static channel_t *_pyepg_channel_find ( const char *id )
 {
-  epggrab_channel_t *ch 
-    = epggrab_module_channel_find(&_pyepg_channels, id);
-  if (ch) return ch->channel;
   return NULL;
 }
 
-static void _pyepg_channel_add ( channel_t *ch )
-{
-  if ( epggrab_module_channel_add(&_pyepg_channels, ch) )
-    _pyepg_save();
-}
-
-static void _pyepg_channel_rem ( channel_t *ch )
-{
-  if ( epggrab_module_channel_rem(&_pyepg_channels, ch) )
-    _pyepg_save();
-}
-
-static void _pyepg_channel_mod ( channel_t *ch )
-{
-  if ( epggrab_module_channel_mod(&_pyepg_channels, ch) )
-    _pyepg_save();
-}
-
 /* **************************************************************************
  * Parsing
  * *************************************************************************/
@@ -397,16 +356,18 @@ static int _pyepg_parse_epg ( htsmsg_t *data, epggrab_stats_t *stats )
       save |= _pyepg_parse_schedule(htsmsg_get_map_by_field(f), stats);
     }
   }
+#if 0
   save |= chsave;
-  if (chsave) _pyepg_save();
+  if (chsave) pyepg_save();
+#endif
 
   return save;
 }
 
-static int _pyepg_parse ( htsmsg_t *data, epggrab_stats_t *stats )
+static int _pyepg_parse 
+  ( epggrab_module_t *mod, htsmsg_t *data, epggrab_stats_t *stats )
 {
   htsmsg_t *tags, *epg;
-  epggrab_module_t *mod;
 
   if ((tags = htsmsg_get_map(data, "tags")) == NULL) return 0;
 
@@ -416,8 +377,8 @@ static int _pyepg_parse ( htsmsg_t *data, epggrab_stats_t *stats )
 
   /* XMLTV format */
   if ((epg = htsmsg_get_map(tags, "tv")) != NULL) {
-    mod = epggrab_module_find_by_name("xmltv");
-    if (mod) return mod->parse(epg, stats);
+    mod = epggrab_module_find_by_id("xmltv_sync");
+    if (mod) return mod->parse(mod, epg, stats);
   }
     
   return 0;
@@ -427,14 +388,12 @@ static int _pyepg_parse ( htsmsg_t *data, epggrab_stats_t *stats )
  * Module Setup
  * ***********************************************************************/
 
-static epggrab_module_t pyepg_module;
-
-static const char* _pyepg_name ( void )
+static void _pyepg_enable ( epggrab_module_t *mod, uint8_t e )
 {
-  return "pyepg";
 }
 
-static htsmsg_t* _pyepg_grab ( const char *iopts )
+
+static htsmsg_t* _pyepg_grab ( epggrab_module_t *mod, const char *icmd, const char *iopts )
 {
   int        i, outlen;
   char       *outbuf;
@@ -479,17 +438,29 @@ static htsmsg_t* _pyepg_grab ( const char *iopts )
   return ret;
 }
 
-epggrab_module_t* pyepg_init ( void )
+void pyepg_init ( epggrab_module_list_t *list )
 {
-  pyepg_module.enable  = NULL;
-  pyepg_module.disable = NULL;
-  pyepg_module.grab    = _pyepg_grab;
-  pyepg_module.parse   = _pyepg_parse;
-  pyepg_module.name    = _pyepg_name;
-  pyepg_module.ch_add  = _pyepg_channel_add;
-  pyepg_module.ch_rem  = _pyepg_channel_rem;
-  pyepg_module.ch_mod  = _pyepg_channel_mod;
-  _pyepg_load();
-  return &pyepg_module;
+  /* Common routines */
+  _pyepg_sync.channels = _pyepg_async.channels = &_pyepg_channels;
+  _pyepg_sync.ch_save  = _pyepg_async.ch_save  = epggrab_module_channels_save;
+  _pyepg_sync.ch_add   = _pyepg_async.ch_add   = epggrab_module_channel_add;
+  _pyepg_sync.ch_rem   = _pyepg_async.ch_rem   = epggrab_module_channel_rem;
+  _pyepg_sync.ch_mod   = _pyepg_async.ch_mod   = epggrab_module_channel_mod;
+  _pyepg_sync.name     = _pyepg_async.name     = strdup("PyEPG");
+
+  /* Sync */
+  _pyepg_sync.id       = strdup("pyepg_sync");
+  _pyepg_sync.path     = strdup("/usr/bin/pyepg");
+  _pyepg_sync.grab     = _pyepg_grab;
+  _pyepg_sync.parse    = _pyepg_parse;
+
+  /* Async */
+  _pyepg_async.id      = strdup("pyepg_async");
+  _pyepg_async.enable  = _pyepg_enable;
+  *((uint8_t*)&_pyepg_async.async) = 1;
+
+  /* Add to list */
+  LIST_INSERT_HEAD(list, &_pyepg_sync, link);
+  LIST_INSERT_HEAD(list, &_pyepg_async, link);
 }
 
index 716baf4310b52e23a66268971fb4674a8070a687..a005c1657a11c7c8ecf171fad4f24b2b66121380 100644 (file)
@@ -21,6 +21,6 @@
 
 #include "epggrab.h"
 
-epggrab_module_t* pyepg_init ( void );
+void pyepg_init ( epggrab_module_list_t *list );
 
 #endif
index 970e8d770cd80ac3953d0acafc3ed14bdece7e5e..f96d982bca62623c614cf0a17d87cce2f599b31c 100644 (file)
@@ -35,6 +35,8 @@
 #include "xmltv.h"
 #include "spawn.h"
 
+#define XMLTV_FIND_GRABBERS "/usr/bin/tv_find_grabbers"
+
 /* **************************************************************************
  * Parsing
  * *************************************************************************/
@@ -381,7 +383,51 @@ static int _xmltv_parse ( htsmsg_t *data, epggrab_stats_t *stats )
 
   return _xmltv_parse_tv(tv, stats);
 }
+#endif
+
+/* ************************************************************************
+ * Config
+ * ***********************************************************************/
 
+#if 0
+static htsmsg_t *xmltv_grabber_list ( void )
+{
+  size_t i, outlen, p, n;
+  char *outbuf;
+  char errbuf[100];
+  htsmsg_t *e = NULL, *array;
+
+  /* Load data */
+  outlen = spawn_and_store_stdout(XMLTV_FIND_GRABBERS, NULL, &outbuf);
+  if ( outlen < 1 ) {
+    tvhlog(LOG_ERR, "xmltv", "%s failed [%s]", XMLTV_FIND_GRABBERS, errbuf);
+    return NULL;
+  }
+
+  /* Process */
+  array     = htsmsg_create_list();
+  p = n = i = 0;
+  while ( i < outlen ) {
+    if ( outbuf[i] == '\n' || outbuf[i] == '\0' ) {
+      outbuf[i] = '\0';
+      e = htsmsg_create_map();
+      htsmsg_add_str(e, "path", &outbuf[p]);
+      htsmsg_add_str(e, "name", &outbuf[n]);
+      htsmsg_add_msg(array, NULL, e);
+      p = n = i + 1;
+    } else if ( outbuf[i] == '|' ) {
+      outbuf[i] = '\0';
+      n = i + 1;
+    }
+    i++;
+  }
+  free(outbuf);
+
+  return array;
+}
+#endif
+
+#if TODO_XMLTV
 /* ************************************************************************
  * Module Setup
  * ***********************************************************************/
@@ -401,7 +447,6 @@ static htsmsg_t* _xmltv_grab ( const char *iopts )
   size_t outlen;
   char *outbuf;
   char errbuf[100];
-  const char *cmd = "/home/aps/tmp/epg.sh";//usr/bin/tv_grab_uk_rt";
 
   /* Debug */
   tvhlog(LOG_DEBUG, "xmltv", "grab %s", cmd);
index bef9e6b9a3f57d98bebb19449dc34723866060d8..b4637a1ae03c2f899d551cc11ff40b138d5e682e 100644 (file)
@@ -19,8 +19,9 @@
 #ifndef EPGGRAB_XMLTV_H
 #define EPGGRAB_XMLTV_H
 
+#include "htsmsg.h"
 #include "epggrab.h"
 
-epggrab_module_t *xmltv_init ( void );
+void xmltv_init ( epggrab_module_list_t *list );
 
 #endif