]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
Migrated epgdb file handling routines to a separate file and change file postfix...
authorAdam Sutton <dev@adamsutton.me.uk>
Fri, 29 Jun 2012 14:15:48 +0000 (15:15 +0100)
committerAdam Sutton <dev@adamsutton.me.uk>
Mon, 30 Jul 2012 14:52:13 +0000 (15:52 +0100)
Makefile
src/epg.c
src/epg.h
src/epgdb.c [new file with mode: 0644]

index 43d95a67ac6f533926c53dae6b57767200790603..640f9f654924d0999c4888db177147b45525218c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -44,6 +44,7 @@ SRCS =  src/main.c \
        src/notify.c \
        src/file.c \
        src/epg.c \
+       src/epgdb.c\
        src/epggrab.c\
        src/spawn.c \
        src/packet.c \
index 1e7c0fef3475c549f5c5391eb4f3167bcc157111..ffe1ca38e55f178b5aa61b1efd3f71029733ef91 100644 (file)
--- a/src/epg.c
+++ b/src/epg.c
@@ -16,8 +16,6 @@
  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <sys/mman.h>
-#include <sys/stat.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include "epg.h"
 #include "dvr/dvr.h"
 #include "htsp.h"
-#include "htsmsg_binary.h"
 #include "epggrab.h"
 
-/* EPG database file */
-#define EPG_DB_OLD "epgdb"
-#define EPG_DB_NEW "epgdb.aps"
-
 /* Broadcast hashing */
 #define EPG_HASH_WIDTH 1024
 #define EPG_HASH_MASK  (EPG_HASH_WIDTH - 1)
@@ -99,242 +92,6 @@ static int _episode_order ( const void *_a, const void *_b )
   return a->epnum.p_num - b->epnum.p_num;
 }
 
-/* **************************************************************************
- * Setup / Update
- * *************************************************************************/
-
-static void _epg_event_deserialize ( htsmsg_t *c, epggrab_stats_t *stats )
-{
-  channel_t *ch;
-  epg_episode_t *ee;
-  epg_broadcast_t *ebc;
-  uint32_t ch_id = 0;
-  uint32_t e_start = 0;
-  uint32_t e_stop = 0;
-  uint32_t u32;
-  const char *title, *desc, *str;
-  char *uri;
-  int save = 0;
-
-  /* Check key info */
-  if(htsmsg_get_u32(c, "ch_id", &ch_id)) return;
-  if((ch = channel_find_by_identifier(ch_id)) == NULL) return;
-  if(htsmsg_get_u32(c, "start", &e_start)) return;
-  if(htsmsg_get_u32(c, "stop", &e_stop)) return;
-  if(!(title = htsmsg_get_str(c, "title"))) return;
-  
-  /* Create broadcast */
-  save = 0;
-  ebc  = epg_broadcast_find_by_time(ch, e_start, e_stop, 0, 1, &save);
-  if (!ebc) return;
-  if (save) stats->broadcasts.total++;
-
-  /* Create episode */
-  save = 0;
-  desc = htsmsg_get_str(c, "desc");
-  uri  = md5sum(desc ?: title);
-  ee   = epg_episode_find_by_uri(uri, 1, &save);
-  free(uri);
-  if (!ee) return;
-  if (save) stats->episodes.total++;
-  if (title)
-    save |= epg_episode_set_title(ee, title);
-  if (desc)
-    save |= epg_episode_set_summary(ee, desc);
-  if (!htsmsg_get_u32(c, "episode", &u32))
-    save |= epg_episode_set_number(ee, u32);
-  if (!htsmsg_get_u32(c, "part", &u32))
-    save |= epg_episode_set_part(ee, u32, 0);
-  if (!htsmsg_get_u32(c, "season", &u32))
-    ee->epnum.s_num = u32;
-  if ((str = htsmsg_get_str(c, "epname")))
-    ee->epnum.text  = strdup(str);
-
-  /* Set episode */
-  save |= epg_broadcast_set_episode(ebc, ee);
-}
-
-static int _epg_write ( int fd, htsmsg_t *m )
-{
-  int ret = 1;
-  size_t msglen;
-  void *msgdata;
-  if (m) {
-    int r = htsmsg_binary_serialize(m, &msgdata, &msglen, 0x10000);
-    htsmsg_destroy(m);
-    if (!r) {
-      ssize_t w = write(fd, msgdata, msglen);
-      free(msgdata);
-      if(w == msglen) ret = 0;
-    }
-  } else {
-    ret = 0;
-  }
-  if(ret) {
-    tvhlog(LOG_ERR, "epg", "failed to store epg to disk");
-    close(fd);
-    hts_settings_remove(EPG_DB_NEW);
-  }
-  return ret;
-}
-
-static int _epg_write_sect ( int fd, const char *sect )
-{
-  htsmsg_t *m = htsmsg_create_map();
-  htsmsg_add_str(m, "__section__", sect);
-  return _epg_write(fd, m);
-}
-
-void epg_save ( void )
-{
-  int fd;
-  epg_object_t *eo;
-  epg_broadcast_t *ebc;
-  channel_t *ch;
-  epggrab_stats_t stats;
-  
-  fd = hts_settings_open_file(1, EPG_DB_NEW);
-
-  memset(&stats, 0, sizeof(stats));
-  if ( _epg_write_sect(fd, "brands") ) return;
-  RB_FOREACH(eo,  &epg_brands, uri_link) {
-    if (_epg_write(fd, epg_brand_serialize((epg_brand_t*)eo))) return;
-    stats.brands.total++;
-  }
-  if ( _epg_write_sect(fd, "seasons") ) return;
-  RB_FOREACH(eo,  &epg_seasons, uri_link) {
-    if (_epg_write(fd, epg_season_serialize((epg_season_t*)eo))) return;
-    stats.seasons.total++;
-  }
-  if ( _epg_write_sect(fd, "episodes") ) return;
-  RB_FOREACH(eo,  &epg_episodes, uri_link) {
-    if (_epg_write(fd, epg_episode_serialize((epg_episode_t*)eo))) return;
-    stats.episodes.total++;
-  }
-  if ( _epg_write_sect(fd, "broadcasts") ) return;
-  RB_FOREACH(ch, &channel_name_tree, ch_name_link) {
-    RB_FOREACH(ebc, &ch->ch_epg_schedule, sched_link) {
-      if (_epg_write(fd, epg_broadcast_serialize(ebc))) return;
-      stats.broadcasts.total++;
-    }
-  }
-
-  /* Stats */
-  tvhlog(LOG_INFO, "epg", "database saved");
-  tvhlog(LOG_INFO, "epg", "  brands     %d", stats.brands.total);
-  tvhlog(LOG_INFO, "epg", "  seasons    %d", stats.seasons.total);
-  tvhlog(LOG_INFO, "epg", "  episodes   %d", stats.episodes.total);
-  tvhlog(LOG_INFO, "epg", "  broadcasts %d", stats.broadcasts.total);
-}
-
-void epg_init ( void )
-{
-  int save, fd;
-  struct stat st;
-  size_t remain;
-  uint8_t *mem, *rp;
-  char *sect = NULL;
-  const char *s;
-  epggrab_stats_t stats;
-  int old = 0;
-  
-  /* Map file to memory */
-  fd = hts_settings_open_file(0, EPG_DB_NEW);
-  if (fd < 0) fd = hts_settings_open_file(0, EPG_DB_OLD);
-  if ( fd < 0 ) {
-    tvhlog(LOG_DEBUG, "epg", "database does not exist");
-    return;
-  }
-  if ( fstat(fd, &st) != 0 ) {
-    tvhlog(LOG_ERR, "epg", "failed to detect database size");
-    return;
-  }
-  if ( !st.st_size ) {
-    tvhlog(LOG_DEBUG, "epg", "database is empty");
-    return;
-  }
-  remain   = st.st_size;
-  rp = mem = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
-  if ( mem == MAP_FAILED ) {
-    tvhlog(LOG_ERR, "epg", "failed to mmap database");
-    return;
-  }
-
-  /* Process */
-  memset(&stats, 0, sizeof(stats));
-  while ( remain > 4 ) {
-
-    /* Get message length */
-    int msglen = (rp[0] << 24) | (rp[1] << 16) | (rp[2] << 8) | rp[3];
-    remain    -= 4;
-    rp        += 4;
-
-    /* Extract message */
-    htsmsg_t *m = htsmsg_binary_deserialize(rp, msglen, NULL);
-
-    /* Process */
-    if(m) {
-
-      /* New section */
-      s = htsmsg_get_str(m, "__section__");
-      if (s) {
-        if (sect) free(sect);
-        sect = strdup(s);
-  
-      /* Assume OLD data */
-      } else if ( !sect ) {
-        if (!old) { 
-          old = 1;
-          tvhlog(LOG_INFO, "epg", "migrating old database");
-        }
-        _epg_event_deserialize(m, &stats);
-
-      /* Brand */
-      } else if ( !strcmp(sect, "brands") ) {
-        if (epg_brand_deserialize(m, 1, &save)) stats.brands.total++;
-        
-      /* Season */
-      } else if ( !strcmp(sect, "seasons") ) {
-        if (epg_season_deserialize(m, 1, &save)) stats.seasons.total++;
-
-      /* Episode */
-      } else if ( !strcmp(sect, "episodes") ) {
-        if (epg_episode_deserialize(m, 1, &save)) stats.episodes.total++;
-  
-      /* Broadcasts */
-      } else if ( !strcmp(sect, "broadcasts") ) {
-        if (epg_broadcast_deserialize(m, 1, &save)) stats.broadcasts.total++;
-
-      /* Unknown */
-      } else {
-        tvhlog(LOG_DEBUG, "epg", "malformed database section [%s]", sect);
-        //htsmsg_print(m);
-      }
-
-      /* Cleanup */
-      htsmsg_destroy(m);
-    }
-
-    /* Next */
-    rp     += msglen;
-    remain -= msglen;
-  }
-  if (sect) free(sect);
-
-  /* Stats */
-  tvhlog(LOG_INFO, "epg", "database loaded");
-  tvhlog(LOG_INFO, "epg", "  channels   %d", stats.channels.total);
-  tvhlog(LOG_INFO, "epg", "  brands     %d", stats.brands.total);
-  tvhlog(LOG_INFO, "epg", "  seasons    %d", stats.seasons.total);
-  tvhlog(LOG_INFO, "epg", "  episodes   %d", stats.episodes.total);
-  tvhlog(LOG_INFO, "epg", "  broadcasts %d", stats.broadcasts.total);
-  tvhlog(LOG_DEBUG, "epg", "next object id %"PRIu64, _epg_object_idx+1);
-
-  /* Close file */
-  munmap(mem, st.st_size);
-  close(fd);
-}
-
 void epg_updated ( void )
 {
   epg_object_t *eo;
index a40527e0e5e36865a07ee7084331ac3a25fc8045..2575fad9c01a80fbad027a41c7466c9cd444a676 100644 (file)
--- a/src/epg.h
+++ b/src/epg.h
@@ -53,7 +53,6 @@ typedef struct epg_broadcast_tree  epg_broadcast_tree_t;
 typedef struct epg_object_list     epg_object_list_t;
 typedef struct epg_object_tree     epg_object_tree_t;
 
-
 /* ************************************************************************
  * Generic Object
  * ***********************************************************************/
diff --git a/src/epgdb.c b/src/epgdb.c
new file mode 100644 (file)
index 0000000..d9006aa
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ *  Electronic Program Guide - Database File functions
+ *  Copyright (C) 2007 Andreas Ă–man
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "tvheadend.h"
+#include "queue.h"
+#include "htsmsg_binary.h"
+#include "settings.h"
+#include "epg.h"
+#include "epggrab.h"
+
+#define EPG_DB_VERSION 2
+
+extern epg_object_tree_t epg_brands;
+extern epg_object_tree_t epg_seasons;
+extern epg_object_tree_t epg_episodes;
+
+/* **************************************************************************
+ * Load
+ * *************************************************************************/
+
+/*
+ * Use for v1 databases
+ */
+static void _epgdb_v1_process ( htsmsg_t *c, epggrab_stats_t *stats )
+{
+  channel_t *ch;
+  epg_episode_t *ee;
+  epg_broadcast_t *ebc;
+  uint32_t ch_id = 0;
+  uint32_t e_start = 0;
+  uint32_t e_stop = 0;
+  uint32_t u32;
+  const char *title, *desc, *str;
+  char *uri;
+  int save = 0;
+
+  /* Check key info */
+  if(htsmsg_get_u32(c, "ch_id", &ch_id)) return;
+  if((ch = channel_find_by_identifier(ch_id)) == NULL) return;
+  if(htsmsg_get_u32(c, "start", &e_start)) return;
+  if(htsmsg_get_u32(c, "stop", &e_stop)) return;
+  if(!(title = htsmsg_get_str(c, "title"))) return;
+  
+  /* Create broadcast */
+  save = 0;
+  ebc  = epg_broadcast_find_by_time(ch, e_start, e_stop, 0, 1, &save);
+  if (!ebc) return;
+  if (save) stats->broadcasts.total++;
+
+  /* Create episode */
+  save = 0;
+  desc = htsmsg_get_str(c, "desc");
+  uri  = md5sum(desc ?: title);
+  ee   = epg_episode_find_by_uri(uri, 1, &save);
+  free(uri);
+  if (!ee) return;
+  if (save) stats->episodes.total++;
+  if (title)
+    save |= epg_episode_set_title(ee, title);
+  if (desc)
+    save |= epg_episode_set_summary(ee, desc);
+  if (!htsmsg_get_u32(c, "episode", &u32))
+    save |= epg_episode_set_number(ee, u32);
+  if (!htsmsg_get_u32(c, "part", &u32))
+    save |= epg_episode_set_part(ee, u32, 0);
+  if (!htsmsg_get_u32(c, "season", &u32))
+    ee->epnum.s_num = u32;
+  if ((str = htsmsg_get_str(c, "epname")))
+    ee->epnum.text  = strdup(str);
+
+  /* Set episode */
+  save |= epg_broadcast_set_episode(ebc, ee);
+}
+
+/*
+ * Process v2 data
+ */
+static void _epgdb_v2_process ( htsmsg_t *m, epggrab_stats_t *stats )
+{
+  int save = 0;
+  const char *s;
+  static char *sect;
+
+  /* New section */
+  if ( (s = htsmsg_get_str(m, "__section__")) ) {
+    if (sect) free(sect);
+    sect = strdup(s);
+  
+  /* Brand */
+  } else if ( !strcmp(sect, "brands") ) {
+    if (epg_brand_deserialize(m, 1, &save)) stats->brands.total++;
+      
+  /* Season */
+  } else if ( !strcmp(sect, "seasons") ) {
+    if (epg_season_deserialize(m, 1, &save)) stats->seasons.total++;
+
+  /* Episode */
+  } else if ( !strcmp(sect, "episodes") ) {
+    if (epg_episode_deserialize(m, 1, &save)) stats->episodes.total++;
+  
+  /* Broadcasts */
+  } else if ( !strcmp(sect, "broadcasts") ) {
+    if (epg_broadcast_deserialize(m, 1, &save)) stats->broadcasts.total++;
+
+  /* Unknown */
+  } else {
+    tvhlog(LOG_DEBUG, "epgdb", "malformed database section [%s]", sect);
+    //htsmsg_print(m);
+  }
+}
+
+/*
+ * Load data
+ */
+void epg_init ( void )
+{
+  int fd = -1;
+  struct stat st;
+  size_t remain;
+  uint8_t *mem, *rp;
+  epggrab_stats_t stats;
+  int ver = EPG_DB_VERSION;
+
+  /* Find the right file (and version) */
+  while (fd < 0 && ver > 0) {
+    fd = hts_settings_open_file(0, "epgdb.v%d", ver);
+    if (fd) break;
+    ver--;
+  }
+  if (!fd)
+    fd = hts_settings_open_file(0, "epgdb");
+  if ( fd < 0 ) {
+    tvhlog(LOG_DEBUG, "epgdb", "database does not exist");
+    return;
+  }
+  
+  /* Map file to memory */
+  if ( fstat(fd, &st) != 0 ) {
+    tvhlog(LOG_ERR, "epgdb", "failed to detect database size");
+    return;
+  }
+  if ( !st.st_size ) {
+    tvhlog(LOG_DEBUG, "epgdb", "database is empty");
+    return;
+  }
+  remain   = st.st_size;
+  rp = mem = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
+  if ( mem == MAP_FAILED ) {
+    tvhlog(LOG_ERR, "epgdb", "failed to mmap database");
+    return;
+  }
+
+  /* Process */
+  memset(&stats, 0, sizeof(stats));
+  while ( remain > 4 ) {
+
+    /* Get message length */
+    int msglen = (rp[0] << 24) | (rp[1] << 16) | (rp[2] << 8) | rp[3];
+    remain    -= 4;
+    rp        += 4;
+    
+    /* Extract message */
+    htsmsg_t *m = htsmsg_binary_deserialize(rp, msglen, NULL);
+
+    /* Next */
+    rp     += msglen;
+    remain -= msglen;
+
+    /* Skip */
+    if (!m) continue;
+
+    /* Process */
+    switch (ver) {
+      case 2:
+        _epgdb_v2_process(m, &stats);
+        break;
+      default: /* v0/1 */
+        _epgdb_v1_process(m, &stats);
+        break;
+    }
+
+    /* Cleanup */
+    htsmsg_destroy(m);
+  }
+
+  /* Stats */
+  tvhlog(LOG_INFO, "epgdb", "loaded v%d", ver);
+  tvhlog(LOG_INFO, "epgdb", "  channels   %d", stats.channels.total);
+  tvhlog(LOG_INFO, "epgdb", "  brands     %d", stats.brands.total);
+  tvhlog(LOG_INFO, "epgdb", "  seasons    %d", stats.seasons.total);
+  tvhlog(LOG_INFO, "epgdb", "  episodes   %d", stats.episodes.total);
+  tvhlog(LOG_INFO, "epgdb", "  broadcasts %d", stats.broadcasts.total);
+
+  /* Close file */
+  munmap(mem, st.st_size);
+  close(fd);
+}
+
+/* **************************************************************************
+ * Save
+ * *************************************************************************/
+
+static int _epg_write ( int fd, htsmsg_t *m )
+{
+  int ret = 1;
+  size_t msglen;
+  void *msgdata;
+  if (m) {
+    int r = htsmsg_binary_serialize(m, &msgdata, &msglen, 0x10000);
+    htsmsg_destroy(m);
+    if (!r) {
+      ssize_t w = write(fd, msgdata, msglen);
+      free(msgdata);
+      if(w == msglen) ret = 0;
+    }
+  } else {
+    ret = 0;
+  }
+  if(ret) {
+    tvhlog(LOG_ERR, "epgdb", "failed to store epg to disk");
+    close(fd);
+    hts_settings_remove("epgdb.v%d", EPG_DB_VERSION);
+  }
+  return ret;
+}
+
+static int _epg_write_sect ( int fd, const char *sect )
+{
+  htsmsg_t *m = htsmsg_create_map();
+  htsmsg_add_str(m, "__section__", sect);
+  return _epg_write(fd, m);
+}
+
+void epg_save ( void )
+{
+  int fd;
+  epg_object_t *eo;
+  epg_broadcast_t *ebc;
+  channel_t *ch;
+  epggrab_stats_t stats;
+  
+  fd = hts_settings_open_file(1, "epgdb.v%d", EPG_DB_VERSION);
+
+  memset(&stats, 0, sizeof(stats));
+  if ( _epg_write_sect(fd, "brands") ) return;
+  RB_FOREACH(eo,  &epg_brands, uri_link) {
+    if (_epg_write(fd, epg_brand_serialize((epg_brand_t*)eo))) return;
+    stats.brands.total++;
+  }
+  if ( _epg_write_sect(fd, "seasons") ) return;
+  RB_FOREACH(eo,  &epg_seasons, uri_link) {
+    if (_epg_write(fd, epg_season_serialize((epg_season_t*)eo))) return;
+    stats.seasons.total++;
+  }
+  if ( _epg_write_sect(fd, "episodes") ) return;
+  RB_FOREACH(eo,  &epg_episodes, uri_link) {
+    if (_epg_write(fd, epg_episode_serialize((epg_episode_t*)eo))) return;
+    stats.episodes.total++;
+  }
+  if ( _epg_write_sect(fd, "broadcasts") ) return;
+  RB_FOREACH(ch, &channel_name_tree, ch_name_link) {
+    RB_FOREACH(ebc, &ch->ch_epg_schedule, sched_link) {
+      if (_epg_write(fd, epg_broadcast_serialize(ebc))) return;
+      stats.broadcasts.total++;
+    }
+  }
+
+  /* Stats */
+  tvhlog(LOG_INFO, "epgdb", "saved");
+  tvhlog(LOG_INFO, "epgdb", "  brands     %d", stats.brands.total);
+  tvhlog(LOG_INFO, "epgdb", "  seasons    %d", stats.seasons.total);
+  tvhlog(LOG_INFO, "epgdb", "  episodes   %d", stats.episodes.total);
+  tvhlog(LOG_INFO, "epgdb", "  broadcasts %d", stats.broadcasts.total);
+}